Python中的迭代器、生成器、装饰器
1. 迭代器
1 """ 2 iterator 3 迭代器协议: 对象必须提供一个next()方法,执行该方法要么返回迭代中的下一项,要么引起一个StopIteration异常,以终止迭代 4 可迭代对象: 实现可迭代协议的对象。(对象内部定义一个__iter__()方法) 5 访问方式:下标方式、迭代器协议、for循环 6 """ 7 8 9 li = [1, 2, 3, 4, 5] 10 iter_li = li.__iter__() # 通过__iter__()方法生成可迭代对象 11 print(iter_li) # <list_iterator object at 0x000002565B5BD748> 12 # print(li[0]) 13 print(iter_li.__next__()) # 1 14 print(next(iter_li)) # 2 15 16 # for 循环访问遵循迭代器访问方式 17 # for i in li: 18 # print(i)
2. 生成器
1 """ 2 generator 3 生成器函数: 定义函数,包换关键字 yield 4 生成器表达式: 三元表达式 5 send() 6 """ 7 8 9 # 生成器函数 10 def generator_func(): 11 yield 1 12 yield 2 13 yield 'louis' 14 yield 'scar' 15 yield 'rose' 16 x = yield 17 print('x=', x) 18 y = yield 19 print('y=', y) 20 21 22 gen = generator_func() 23 print(gen) # <generator object generator_func at 0x000001A5464A2F48> 24 print(gen.__next__()) 25 print(gen.__next__()) 26 print(gen.__next__()) 27 print(gen.__next__()) 28 print(gen.__next__()) 29 print(gen.__next__()) # None 30 # 改变x的值并触发 __next()__ 31 res = gen.send('init_') 32 print(res) # x= init_ None 33 34 # 生成器表达式 35 count1 = [x for x in range(10)] # 列表表达式 36 print(count1) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 37 count2 = (x for x in range(10) if x > 5) # 生成器表达式 38 print(count2) # <generator object <genexpr> at 0x000001E364E87840> 39 print(list(count2)) # [6, 7, 8, 9] 40 41 42 import time 43 44 45 # 生产者消费者模型 46 def consumer(name): 47 print('消费者[%s]开始下单' % name) 48 while True: 49 num = yield 50 time.sleep(0.5) 51 print('%s 第[%s]杯奶茶' % (name, num)) 52 53 54 def producer(): 55 c1 = consumer('louis') 56 c2 = consumer('scar') 57 next(c1) 58 next(c2) 59 for i in range(1, 10): 60 c1.send(i) 61 c2.send(i) 62 63 64 producer()
运行结果:
消费者[louis]开始下单
消费者[scar]开始下单
louis 第[1]杯奶茶
scar 第[1]杯奶茶
louis 第[2]杯奶茶
scar 第[2]杯奶茶
louis 第[3]杯奶茶
scar 第[3]杯奶茶
louis 第[4]杯奶茶
scar 第[4]杯奶茶
louis 第[5]杯奶茶
scar 第[5]杯奶茶
louis 第[6]杯奶茶
scar 第[6]杯奶茶
louis 第[7]杯奶茶
scar 第[7]杯奶茶
louis 第[8]杯奶茶
scar 第[8]杯奶茶
louis 第[9]杯奶茶
scar 第[9]杯奶茶
3 装饰器
a. 装饰器实现日志操作(带参以及不带参的装饰器函数)
1 """ 2 装饰器:本质就是函数,功能就是为其它函数添加附加功能 3 使用场景: 插入日志、性能测试、事务处理、缓存、权限校验等 4 语法糖: @def_func(func) 5 装饰器 = 高阶函数 + 函数嵌套 + 闭包 6 高阶函数: 函数的接受的参数是一个函数,返回值也是一个函数 7 函数嵌套: 在函数里面执行其它函数 8 闭包: 主要看作用域范围 9 """ 10 import functools 11 12 13 def func_logging(arg): 14 print(arg) 15 if callable(arg): # 如果装饰器不带参数 16 # @functools.wraps(arg) 17 def _deco(*args, **kwargs): 18 print('%s is running' % arg.__name__) 19 arg(*args, **kwargs) 20 return _deco 21 else: # 如果装饰器带参数 22 def _deco(func): 23 @functools.wraps(func) 24 def __deco(*args, **kwargs): 25 if arg == 'warn': 26 print('warn %s is running' % func.__name__) 27 return func(*args, **kwargs) 28 return __deco 29 return _deco 30 31 32 @func_logging # test1 = func_logging(test) 33 def test1(): 34 print('this is test1') 35 print(test1.__name__) 36 37 38 @func_logging('warn') # 直接执行 func_logging() 返回装饰器函数 _deco() 39 def test2(): 40 print('this is test2') 41 print(test2.__name__) 42 43 44 test1() 45 # <function test1 at 0x000002335B5A1EA0> 46 # test1 is running 47 # this is test1 48 # test1 49 # 函数名变为_deco而不是test1,这个情况在使用反射的特性的时候就会造成问题。因此引入了functools.wraps解决这个问题 50 test2() 51 # warn 52 # warn test2 is running 53 # this is test2 54 # test2
b. 性能测试
1 import time 2 import functools 3 # 性能测试 4 def timer(func): 5 @functools.wraps(func) 6 def warpper(*args, **kwargs): 7 print('%s is start running' % func.__name__) 8 start_time = time.time() 9 func(*args, **kwargs) 10 stop_time = time.time() 11 print('%s is stop running, cost %s s' % (func.__name__, stop_time - start_time)) 12 return warpper 13 14 15 @timer 16 def test3(): 17 time.sleep(1.0) 18 print(test3.__name__) 19 20 21 test3() 22 # test3 is start running 23 # test3 24 # test3 is stop running, cost 1.0015299320220947 s