From:http://learnpythonthehardway.org/book/ex37.html
1. with X as Y: pass
1.1 yield
2. exec
2.1 namespace
KEYWORD | DESCRIPTION | EXAMPLE |
---|---|---|
and | Logical and. | True and False == False |
as (1) | Part of the with-as statement. | with X as Y: pass |
assert | Assert (ensure) that something is true. | assert False, "Error!" |
break | Stop this loop right now. | while True: break |
class | Define a class. | class Person(object) |
continue | Don‘t process more of the loop, do it again. | while True: continue |
def | Define a function. | def X(): pass |
del | Delete from dictionary. | del X[Y] |
elif | Else if condition. | if: X; elif: Y; else: J |
else | Else condition. | if: X; elif: Y; else: J |
except | If an exception happens, do this. | except ValueError, e: print e |
exec (2) | Run a string as Python. | exec ‘print "hello"‘ |
finally | Exceptions or not, finally do this no matter what. | finally: pass |
for | Loop over a collection of things. | for X in Y: pass |
from | Importing specific parts of a module. | from x import Y |
global | Declare that you want a global variable. | global X |
if | If condition. | if: X; elif: Y; else: J |
import | Import a module into this one to use. | import os |
in | Part of for-loops. Also a test of X in Y. | for X in Y: pass also 1 in [1] == True |
is | Like == to test equality. | 1 is 1 == True |
lambda (3) | Create a short anonymous function. | s = lambda y: y ** y; s(3) |
not | Logical not. | not True == False |
or | Logical or. | True or False == True |
pass (4) | This block is empty. | def empty(): pass |
Print this string. | print ‘this string‘ | |
raise (5) | Raise an exception when things go wrong. | raise ValueError("No") |
return | Exit the function with a return value. | def X(): return Y |
try | Try this block, and if exception, go to except. | try: pass |
while | While loop. | while X: pass |
with | With an expression as a variable do. | with X as Y: pass |
yield (1.1) | Pause here and return to caller. | def X(): yield Y; X().next() |
1. with-as statement(也称context manager)
From: http://zhoutall.com/archives/325
(1) 常见写法,但比较啰嗦
try: f = open(‘xxx‘) except: print ‘fail to open‘ exit(-1) try: do something except: do something finally: f.close()
(2) 使用封装如何?不用反复写finally,但导致:所有的函数都要被 controlled_execution( ) 下,太累赘。
def controlled_execution(callback): set things up try: callback(thing) finally: tear things down def my_function(thing): do something controlled_execution(my_function)
(3) 另一个办法是使用生成器,但是只需要生成一次数据,我们用for-in结构去调用他:
def controlled_execution(): //因为thing只有一个,所以yield语句只需要执行一次,从代码可读性也就是优雅的角度来说这简直是糟糕透了 set things up try: yield thing //--> see "yield" finally: tear things down for thing in controlled_execution(): do something with thing
(4) with-as新方案
class controlled_execution: def __enter__(self): set things up return thing def __exit__(self, type, value, traceback): tear things down with controlled_execution() as thing: do something
当python执行这一句时,会调用__enter__函数,然后把该函数return的值传给as后指定的变量。之后,python会执行下面do something的语句块。最后不论在该语句块出现了什么异常,都会在离开时执行__exit__。
另外,__exit__除了用于tear things down,还可以进行异常的监控和处理,注意后几个参数。要跳过一个异常,只需要返回该函数True即可。
在python2.5及以后,file对象已经写好了__enter__和__exit__函数,我们可以这样测试:
>>> f = open("x.txt") >>> f <open file ‘x.txt‘, mode ‘r‘ at 0x00AE82F0> >>> f.__enter__() <open file ‘x.txt‘, mode ‘r‘ at 0x00AE82F0> >>> f.read(1) ‘X‘ >>> f.__exit__(None, None, None) >>> f.read(1) Traceback (most recent call last): File "<stdin>", line 1, in <module>
之后,我们如果要打开文件并保证最后关闭他,只需要这么做:
with open("x.txt") as f: data = f.read() do something with data
如果有多个项,我们可以这么写:
with open("x.txt") as f1, open(‘xxx.txt‘) as f2: do something with f1,f2
上文说了__exit__函数可以进行部分异常的处理,如果我们不在这个函数中处理异常,他会正常抛出,这时候我们可以这样写(python 2.7及以上版本,之前的版本参考使用contextlib.nested这个库函数):
try: with open( "a.txt" ) as f : do something except xxxError: do something about exception
总之,with-as表达式极大的简化了每次写finally的工作,这对保持代码的优雅性是有极大帮助的。
1.1 yield
From: http://www.ibm.com/developerworks/cn/opensource/os-cn-python-yield/
清单 1. 简单输出斐波那契數列前 N 个数
def fab(max): n, a, b = 0, 0, 1 while n < max: print b // 不太好! 其实改为yield就好了。 a, b = b, a + b n = n + 1
执行 fab(5),我们可以得到如下输出:
>>> fab(5) 1 1 2 3 5
结果没有问题,但有经验的开发者会指出,直接在 fab 函数中用 print 打印数字会导致该函数可复用性较差,因为 fab 函数返回 None,其他函数无法获得该函数生成的数列。
要提高 fab 函数的可复用性,最好不要直接打印出数列,而是返回一个 List。
以下是 fab 函数改写后的第二个版本:
清单 2. 输出斐波那契數列前 N 个数第二版
def fab(max): n, a, b = 0, 0, 1 L = [] while n < max: L.append(b) a, b = b, a + b n = n + 1 return L // 暂用内存太大!
可以使用如下方式打印出 fab 函数返回的 List:
>>> for n in fab(5): ... print n ... 1 1 2 3 5
改写后的 fab 函数通过返回 List 能满足复用性的要求,但是更有经验的开发者会指出,该函数在运行中占用的内存会随着参数 max 的增大而增大。
如果要控制内存占用,最好不要用 List来保存中间结果,而是通过 iterable 对象来迭代。例如,在 Python2.x 中,代码:
清单 3. 通过 iterable 对象来迭代
for i in range(1000): pass //会导致生成一个 1000 个元素的 List
for i in xrange(1000): pass // iterable对象是解决的办法!
在每次迭代中返回下一个数值,内存空间占用很小。因为 xrange 不返回 List,而是返回一个 iterable 对象。
利用 iterable 我们可以把 fab 函数改写为一个支持 iterable 的 class,以下是第三个版本的 Fab:
清单 4. 第三个版本
class Fab(object): def __init__(self, max): self.max = max self.n, self.a, self.b = 0, 0, 1 def __iter__(self): return self def next(self): if self.n < self.max: r = self.b self.a, self.b = self.b, self.a + self.b self.n = self.n + 1 return r raise StopIteration()
Fab 类通过 next() 不断返回数列的下一个数,内存占用始终为常数:
>>> for n in Fab(5): ... print n ... 1 1 2 3 5
然而,使用 class 改写的这个版本,代码远远没有第一版的 fab 函数来得简洁。
如果我们想要保持第一版 fab 函数的简洁性,同时又要获得 iterable 的效果,yield 就派上用场了:
清单 5. 使用 yield 的第四版
def fab(max): n, a, b = 0, 0, 1 while n < max: yield b # print b a, b = b, a + b n = n + 1
第四个版本的 fab 和第一版相比,仅仅把 print b 改为了 yield b,就在保持简洁性的同时获得了 iterable 的效果。
调用第四版的 fab 和第二版的 fab 完全一致:
>>> for n in fab(5): // for执行一次函数,其实只是调用了函数内的一次运算;再调一次就再继续算一次! ... print n ... 1 1 2 3 5
也可以手动调用 fab(5) 的 next() 方法(因为 fab(5) 是一个 generator 对象,该对象具有 next() 方法),这样我们就可以更清楚地看到 fab 的执行流程:
清单 6. 执行流程
>>> f = fab(5) // fab(5) 是iterable function,这里就是指的fab的实例 >>> f.next() // 与清单4 中的next比较下,其实是相同的思想 1 >>> f.next() 1 >>> f.next() 2 >>> f.next() 3 >>> f.next() 5 >>> f.next() Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration
当函数执行结束时,generator 自动抛出 StopIteration 异常,表示迭代完成。在 for 循环里,无需处理 StopIteration 异常,循环会正常结束。
2. exec
From: http://blog.sina.com.cn/s/blog_76e94d210100w1bl.html
exec
语句用来执行储存在字符串或文件中的Python语句。
例如,我们可以在运行时生成一个包含Python代码的字符串,然后使用exec
语句执行这些语句。
下面是一个简单的例子。
>>> exec ‘print "Hello World"‘ Hello World
eval
语句用来计算存储在字符串中的有效Python表达式。下面是一个简单的例子。
>>> eval_r(‘2*3‘) 6
eval_r(str [ globals [ locals ]])函数将字符串str当成有效python表达式来求值,并返回计算结果。
同样地, exec语句将字符串str当成有效Python代码来执。.提供给exec的代码的名称空间和exec语句的名称空间相同。
最后,execfile(filename [, globals [, locals ]]) 函数可以用来执行一个文件。
>>> eval_r(‘3+4‘) 7 >>> exec ‘a=100‘ >>> a 100 >>> execfile(r‘d:\code\ex\test.py‘) hello world! >>>
默认的,eval_r(), exec, execfile() 所运行的代码都位于当前的名字空间中.
eval_r(), exec 和 execfile()函数 也可以接受一个或两个可选字典参数作为代码执行的全局名字空间和局部名字空间。
2.1 Python命名空间和作用域
From: http://blog.cipherc.com/2015/04/25/python_namespace_and_scope/#assignment-rule