一闭三器
所谓一闭三器,是指闭包、装饰器、迭代器、生成器。
一、闭包
内部函数引用外部函数的变量(非全局变量),外部函数返回内部函数(返回内部函数的函数名),内部函数就是闭包函数。
所以闭包有以下特点:
- 函数嵌套
- 内部函数使用外部函数的变量
- 外部函数返回内部函数名
示例1:
def outer(m): def inner(n): return print(m + n) return inner func1 = outer(10) # func1相当于inner,m=10 func1(20) # 相当于inner(20), m=10,n=20
示例2:
def outer(): m = 10 print(m) def inner(n): m = 20 # 相当于在内层函数中新定义了一个变量,和外层函数的m无关,不会影响到外层函数的m return print(f'内层m:{m} n:{n} ') inner(3) print(f'外层m:{m}') return inner func1 = outer() # 10 # 内层m:20 n:3 # 外层m:10
内层函数中对和外层函数同名的变量进行赋值时,是在内层新声明了一个和外层函数变量同名的变量,不会对外层函数的变量产生影响,类似局部变量和全局变量的关系。
二、装饰器 Decorator
装饰器的本质是一个闭包。装饰器可以在不改变函数功能的基础上,给函数增加一些功能。装饰器可以让代码更简洁。
示例1:
def external(func): def inner(): print('start') func() print('end') return inner @external def sport(): print('sport') @external def game(): print('game') return 'happy' sport() g = game() print(g) # None
由于装饰器external的内部函数inner没有返回值,被装饰的game函数也无法获取返回值。因此可以改进如下:
示例2:
def external(func): def inner(): print('start') res = func() print('end') return res return inner @external def sport(): print('sport') @external def game(): print('game') return 'happy' sport() # start # sport # end g = game() # start # game # end print(g) # happy
如果sport和game函数有参数,且参数个数不同,要能同时对sport和game函数进行装饰,可以改进如下:
示例3:
def external(func): def inner(*args, **kwargs): # 可以接收任意参数 print('start') res = func(*args, **kwargs) print('end') return res return inner @external def sport(name, addr): print(f'{name} do sport {addr}') @external def game(hours): print(f'game {hours} hours') return 'happy' sport('tom', 'outside') # start # tom do sport outside # end g = game(3) # start # game 3 hours # end
三、迭代器 iterator
迭代器(iterator)与可迭代对象(iterable)
- 可以用for循环遍历的对象,都是可迭代对象。可迭代对象包含 iter() 方法。(__iter__())
- 迭代器是可迭代的对象,
str = '大家好' str2 = str.__iter__() # 或 str2 = iter(str) print(str2) # <str_iterator object at 0x000001D8869CAC20> print(str2.__next__()) # 大 print(next(str2)) # 家 print(next(str2)) # 好
迭代器从第一个元素开始访问,直到访问所有元素时结束。
while循环遍历迭代器:
iter1 = '大家好'.__iter__() while True: try: print(next(iter1)) except StopIteration: break
四、生成器 generator
生成器的本质就是迭代器。在每次迭代时返回一个值,直到抛出 StopIteration 异常。
创建生成器的方式:
(1)生成器函数
使用关键字 yield,函数中出现了 yield,那该函数就是一个生成器函数;生成器函数执行的时候,并不会立即执行函数,得到的是生成器。
def func1(): print('hello') yield '你好' f = func1() print(f) # <generator object func1 at 0x0000029349D7C6D0> ret = f.__next__() # hello print(ret) # 你好
def func2(): print('第一部分') yield 'aaa' print('第二部分') yield 'bbb' f = func2() res1 = next(f) # 第一部分 print(res1) # aaa res2 = next(f) # 第二部分 print(res2) # bbb
和 return 相比,yield 除了可以返回相应的值,还有一个更重要的功能,即每当程序执行完该语句时,程序就会暂停执行。
不仅如此,即便调用生成器函数,Python 解释器也不会执行函数中的代码,它只会返回一个生成器(对象)
def func3(): list1 = [] for i in range(1, 11): list1.append(f'No {i}') yield list1 # 前面for循环执行完毕才到该行 yield,因此list1有10个元素 f = func3() print(f) # <generator object func3 at 0x000002B7C060DD20> print(f.__next__()) # ['No 1', 'No 2', 'No 3', 'No 4', 'No 5', 'No 6', 'No 7', 'No 8', 'No 9', 'No 10']
(2)生成器表达式
(表达式 for 变量 in 序列 if 条件)
列表生成式中提过,使用小括号的生成式并不是返回一个元组,而是返回一个生成器对象。
g = (x for x in range(1, 11) if x % 2 == 0) print(g) # <generator object <genexpr> at 0x0000023A9728DD20> print(next(g)) # 2 print(next(g)) # 4 print(next(g)) # 6
浙公网安备 33010602011771号