本文主要讲解装饰器、迭代器、生成器、上下文管理器以及惰性计算
装饰器(decorator)
-
功能:增加函数的功能,而不引入多余的变量,不需要修改原来的函数;
-
实现:利用@语法糖,将被装饰函数作为第一位置参数传给装饰器;
def dec1(func): print("2") def one(): print("3") func() print("6") return one def dec2(func): print("1") def two(): print("4") func() print("5") return two @dec1 @dec2 def test(): print("hello world!") test()
输出:
1 2 3 4 hello world! 5 6
-
模块加载与导入时立即执行,不需要显示的调用
-
利用闭包可以实现带参数的装饰器
迭代器(iterator)
- 可迭代对象: 可返回迭代器的对象,如容器中的list、dict、set、str;
- 迭代器: 用iter()封装可迭代对象,用next()访问元素;
- 任何实现了__iter__()和__next__()方法的对象都是迭代器,__iter__返回迭代器自身,__next__返回容器中的下一个值,如果容器中没有更多元素了,则抛出StopIteration异常;
>>> x = [1, 2, 3] # x为容器 >>> y = iter(x) # y为迭代器 >>> z = iter(x) # z与y独立 >>> next(y) # 调用迭代器 1 >>> next(y) 2 >>> next(z) 1
- 优点: 不要求事先准备好整个迭代过程中所有的元素,适合于非常大的序列的访问;
- for循环: 作用于可迭代对象,Python将自动调用工厂函数iter()获得迭代器,自动调用next()获取下一个元素;
生成器(generator)
- 迭代器实现起来有些繁琐,生成器则自动的实现了迭代器协议,一边循环,一边计算;
两种实现方式:
-
1 yield: 生成器函数,暂时,下次继续
def f(): yield 1 yield 2 yield 3 f1=f() print([next(f1) for i in range(2)]) 输出:[1, 2]
-
2 generation expression: 生成器表达式,用(),与list不同;
>>> a = (x for x in range(10)) >>> next(a) 0 >>> next(a) 1 >>> next(a) 2
-
生成器本身是一个迭代器,可用next()调用
>>> from collections import Iterable >>> isinstance((x for x in range(10)), Iterable) True
-
生成器生成斐波那契数列
def fibonacci(): a = [1, 1] while True: a.append(sum(a)) yield a.pop(0) for x in fibonacci(): print(x) if x > 50: break
输出:
1 1 2 3 5 8 13 21 34
-
生成器好处: 相比起list,能节省大量内存,尤其是对于无法在内存中存放的无限数据流
上下文管理器(context manager)
- 有始必有终的代码使用,非常pythonic,减少错误,提高可读性;
- 为什么需要:程序运行中突然中断或出现bug,比如写入文件,加了上下文管理器可以将后续关闭文件等操作完成,类似于try/finally,否则则不会保存;
with open(path, mode) as f: f.read()
执行时机:
__init__()
:进入with语句时执行__enter__()
:进入with代码块之前执行__exit__()
:离开或者突然中断时先执行
计时:
import time
class timer:
def __init__(self, name):
self.name=name
def __enter__(self):
self.start=time.time()
def __exit__(self):
self.end=time.time()
self.interval = self.end - self.start
print("%s took: %0.3f seconds" % (self.name, self.interval))
with timer("sleep 3 seconds"):
time.sleep(3)
惰性计算
- 函数在定义的时候,并没有分配内存空间用来保存任何变量的值,只有在执行的时候,才会分配空间,保存变量的值
>>> a = [lambda :x for x in range(10)] >>> a[0]() 9 >>> a[9]() 9
解释
:首先这是个列表解析表达式,列表中的每一个元素是一个函数,返回x的值,但没有执行函数调用的时候,是没有x的值的;
当后续调用时,for循环中的x对于所有的函数是公用的,此时的x的值已经变为9,因此无论调用哪个元素,结果都为9; - 同样的例子:
输出:flist = [] for i in range(3): def foo(x): print x + i flist.append(foo) for f in flist: f(2)
4 4 4
- 生成器与迭代器,处理无限的数据流时,逐个计算;