六、迭代器、生成器和装饰器
1.迭代器
-
定义
能被next()函数进行调用且不断返回下一个值的对象。其内置方法中包含
__iter__
(返回迭代器本身)和__next__
(返回容器的下一个元素)。 -
特征
迭代器会生成惰性序列,它通过计算把值依次的返回,一边循环一边计算,而不是一次性得到所有的数据。
-
优点
需要数据的时候,一次取一个,可以在很大程度上节省内容空间,而不是一次性把所有的数据存入内存中;此外,可以遍历无限量的数据。
-
创建
使用
iter()
函数来创建。string = iter('abcd') print(next(string)) print(next(string)) print(next(string)) print(next(string)) # 遍历完成之后继调用 print(next(string)) # 输出结果 StopIteration a b c d # 注意:当遍历完序列时,会引发一个StopIteration异常。使用for循环可以规避整个问题(for循环的底层使用了next方法)。 string = iter('abcd') for item in string: print(item) # 输出结果 a b c d
2. 生成器
-
定义
包含了yield语句的函数。
-
特征
执行生成器函数时,其内部代码不执行,而是返回一个生成器对象(特殊的迭代器)。生成器可以暂停函数并返回一个中间结果(遇到yield本次循环就终止,并返回yield后的值),可以被for循环或者用next函数逐个取值。
-
格式
# 格式一 def fun(): print('第一次执行') yield 1 print('第二次执行') yield 2 print('第三次执行') yield 3 result = fun() print(result, type(result)) for i in result: print(i) # 格式二 def fun(): print('第一次执行') yield 1 print('第二次执行') yield 2 print('第三次执行') yield 3 result = fun() print(next(result)) print(next(result)) print(next(result)) # 输出结果 <generator object fun at 0x000001A203DD5A20> <class 'generator'> 第一次执行 1 第二次执行 2 第三次执行 3
-
注意
生成器中不能包含return语句,遇到return语句则会结束生成器。
def fun(): print('第一次执行') yield 1 print('第二次执行') yield 2 return 123 print('第三次执行') yield 3 for i in fun(): print(i) # 输出结果 第一次执行 1 第二次执行 2
-
生成器推导式
result = (lambda: i ** 2 for i in range(1, 5)) print(type(result)) for i in result: print(i()) # 输出结果 <class 'generator'> 1 4 9 16 # 对比列表推导式 result = [lambda: i ** 2 for i in range(1, 5)] print(type(result)) for i in result: print(i()) # 输出结果 <class 'list'> 16 16 16 16
3. 装饰器
-
定义
在不改变原函数内部代码的基础上,在函数执行之前和之后自动执行某个功能。
-
装饰器编写格式
def 外层函数(传入参数): def 内层函数(*args, **kwargs): result = 传入参数(*args, **kwargs) return result return 内层函数
-
装饰器应用格式
@外层函数 def index(): pass index()
-
作用
# 和index函自身相比,使用装饰器之后,执行index函数可以在原函数的基础上多执行print('执行原函数前')和print('执行原函数后')两条语句,此处是以最简单的方式来进行说明,完全可以根据需求将这两个语句换成功能更复杂的语句块。 def 外层函数(传入参数): def 内层函数(*args, **kwargs): print('执行原函数前') result = 传入参数(*args, **kwargs) # 执行原函数并返回值 print('执行原函数后') return result return 内层函数 @外层函数 def index(): pass index()
-
例子
def fun(arg): def inner(): print('执行函数前添加的功能:', 1) v = arg() print('执行函数后添加的功能:', 3) return v return inner # 第一步:执行fun函数并将下面的函数作为参数传递,相当于:fun(index) # 第二步:将fun的返回值重新赋值给下面的函数名,相当于:index = fun(index) @fun def index(): print('函数自己的功能:', 2) return 666 index() # 输出结果为 执行函数前添加的功能: 1 函数自己的功能: 2 执行函数后添加的功能: 3 # 若没有@fun语句(没有使用装饰器),输出结果为 函数自己的功能: 2
-
带参数的装饰器
# 可以用于连续多次重复执行函数 def with_parameter(count): def outer(arg): def inner(): for i in range(count): print('\n第%d次执行' % (i + 1)) print('执行函数前添加的功能:', 1) v = arg() print('执行函数后添加的功能:', 3) return v return inner return outer # 相当于:index = with_parameter(3)(index) @with_parameter(3) def index(): print('函数自己的功能:', 2) return 666 result = index() print('\n函数最后的返回结果:', result) # 输出结果 第1次执行 执行函数前添加的功能: 1 函数自己的功能: 2 执行函数后添加的功能: 3 第2次执行 执行函数前添加的功能: 1 函数自己的功能: 2 执行函数后添加的功能: 3 第3次执行 执行函数前添加的功能: 1 函数自己的功能: 2 执行函数后添加的功能: 3 函数最后的返回结果: 666
-
装饰器的嵌套
def outer1(fun): def inner1(): print('This is 001') result1 = fun() print('This is 002') return result1 return inner1 def outer2(fun): def inner2(): print('This is 003') result2 = fun() print('This is 004') return result2 return inner2 @outer1 @outer2 def origin(): print('This is initial') origin() # 输出结果 This is 001 This is 003 This is initial This is 004 This is 002 ''' 逻辑法分析: 步骤一:origin = outer2(origin),outer2(origin) == inner2 步骤二:origin = outer1(outer2(origin)),origin = outer1(inner2),outer1(inner2) == inner1 步骤三:执行origin()等价于inner1(),此时输出This is 001;接着执行inner2(),此时输出This is 003;然后执行origin()原函数,此时输出This is initial;origin()原函数执行完毕,接着输出This is 004;inner2()执行完毕,接着输出This is 002,至此,整个函数执行完毕。 ''' ''' 装饰器思想法分析: outer2是origin的装饰器,outer1又是outer2的装饰器。 因此,在执行该嵌套装饰器时,outer1的目的是在未改变outer2的情况下,在其执行前后添加所需的功能,所以outer1的'This is 001'最先输出,接着输出outer2的内容。而outer2是origin的装饰器,所以outer2的目的是在未改变origin的情况下,在其执行前后添加所需的功能,所以outer的'This is 003'先输出,接着输出origin的'This is initial',然后输出outer2的'This is 004',最后输出outer1的'This is 002'。 ''' # 注意:多层装饰器嵌套时,按从下往上的方向执行。