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

 

posted @ 2020-02-19 21:48  待我身高一米八  阅读(216)  评论(0编辑  收藏  举报