一、装饰器
1、什么是装饰器
1)定义:本质就是函数;目的是为其他函数添加附加功能。
2)原则:1、不能修改被装饰函数的源代码。
2、不能修改被装饰函数的调用方式。
#即:装饰器对被修改函数是完全透明的。
3)知识点:
# 1、函数即‘变量’
# 2、高阶函数
# 3、嵌套函数
4)装饰器 <= 高阶函数 + 嵌套函数。
2、函数即“变量”
与其他高级语言类似,Python不支持函数在未声明之前,对其进行引用或者调用。与变量类似,函数定义也是存在定义和调用两个过程。
1 # 定义变量 2 a = 1 3 #使用变量 4 print(a) 5 6 #定义函数 7 def test(): 8 print('in the fnc test.') 9 10 #调用函数 11 print(test) #函数引用 12 test() 13 14 test1 = test #函数可像变量一样传递 15 print(test1) 16 test1()
1 print('函数调用顺序'.center(50,'-')) 2 def foo(): 3 print('in the fnc doo') 4 bar() 5 6 def bar(): 7 print('in the fnc bar') 8 9 foo() 10 #只需在调用前声明了,foo和bar函数即可,与顺序无关。 11 #调试一次即可发现。
3、高阶函数
1)、把一个函数当做实参传递给另外一个函数。
2)、返回值是一个函数。
满足以上任意条件,这个函数就是高阶函数。
1 import time 2 def bar(): 3 time.sleep(1) 4 print('in the fnc bar') 5 6 #1、把一个函数当做实参传递给另外一个函数 7 def f_gj1(fnc): 8 s_time = time.time() 9 fnc() 10 e_time = time.time() 11 print('the fnc [%s] running time is %s'%(fnc,e_time-s_time)) 12 13 def f_gj2(fnc): 14 print(fnc) 15 return fnc 16 17 #1、拓展了函数功能,没有修改源代码;但是修改了函数调用方式。 18 f_gj1(bar) 19 20 #2、不修改函数调用方式,没有修改源代码;但是貌似附加功能有限。 21 bar = f_gj2(bar) 22 bar()
4、嵌套函数
在函数体内,申明一个函数,这个函数就是嵌套函数。
1 def foo(): 2 print('in the fnc foo') 3 def bar(): 4 print('in the fnc bar') 5 6 bar() 7 8 foo() 9 10 #foo1不是嵌套函数 11 #错误示范 12 def foo1(): 13 print('in the fnc doo') 14 bar1() 15 16 def bar1(): 17 print('in the fnc bar')
foo是嵌套函数,foo1不是。
5、装饰器使用
1 import time 2 #高阶函数(返回一个高阶函数(参数传递形式)) 3 def timer(fnc): 4 def deco(): 5 s_time = time.time() 6 res = fnc() 7 e_time = time.time() 8 print('the fnc running time is %s'%(e_time-s_time)) 9 return res 10 return deco 11 12 @timer # bar = timer(bar) --> bar = timer(bar) = deco 13 def bar(): 14 time.sleep(1) 15 print('in the fnc bar') 16 return 'fnc res from bar' 17 18 print(bar()) 19 #调试一次,更加透彻理解。 20 #完美,附加了功能,没有修改源代码,没有修改调用方式。但是,函数有参数时,出错!
1 import time 2 #高阶函数(返回一个高阶函数(参数传递形式)) 3 def timer(fnc): 4 def deco(*args,**kwargs): 5 s_time = time.time() 6 res = fnc(*args,**kwargs) 7 e_time = time.time() 8 print('the fnc running time is %s'%(e_time-s_time)) 9 return res 10 return deco 11 12 @timer # bar = timer(bar) --> bar = timer(bar) = deco 13 def bar(): 14 time.sleep(1) 15 print('in the fnc bar') 16 return 'fnc res from bar' 17 18 @timer # test5 = timer(test5) --> test5 = timer(test5) = deco 19 def test5(x,y=2,*args,**kwargs): 20 print(x,y) 21 print(args) 22 print(kwargs) 23 return 'fnc res from test5!' 24 25 26 print(bar()) 27 print('分割线'.center(50,'-')) 28 print(test5(1,3,4,5,6,name='a',age=8)) 29 #完美解决,参数问题。
之前的装饰器都是只能实现一种功能,若需要根据条件确定其附近功能呢?
初始网站不需要登陆都能使用,后续需要用户登陆才能查看部分页面。
其中,index 不需要登陆,home本地登陆验证,bbs:ldap远程登陆验证(不知道这是什么毛线)
#带参数的装饰器:加多一层函数嵌套 _username = 'cz' _password = '123' def login_type(l_type): print('login type: ',l_type) def login(fnc): def deco(*args,**kwargs): if l_type == 'local': username = input('username: ') password = input('password: ') if _username == username and _password == password: print('Welcome user {name} login...'.format(name=username)) res = fnc() return res else: print('Invalid username or password!') elif l_type == 'ldap': print('ldap 搞毛线,直接上吧。。。') res = fnc() return res return deco return login def index(): print('welcome to index page!'.rjust(50,'.')) @login_type('local') # login_type('local') & home = login(home) = deco def home(): print('welcome to home page!'.rjust(50,'.')) @login_type('ldap') def bbs(): print('welcome to bbs page!'.rjust(50,'.')) index() home() bbs()
装饰器相关代码,应加断点,全部调试一次。可加深理解。
二、生成器
1、什么是生成器
1 #通过列表生成式,我们可以直接创建一个列表。 2 # 但是,受到内存限制,列表容量肯定是有限的。 3 # 而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间, 4 # 如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。 5 # 所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢? 6 # 这样就不必创建完整的list,从而节省大量的空间。 7 # 在Python中,这种一边循环一边计算的机制,称为生成器:generator。 8 # 要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator: 9 a = [ i+1 for i in range(10)] 10 print(a) 11 12 b = ( i+1 for i in range(10)) 13 print(b) 14 15 print(b.__next__()) 16 print(b.__next__()) 17 18 #b[5] #TypeError: 'generator' object is not subscriptable 19 #generator保存的是算法:每次调用next,就计算出下一个元素的值,直到计算到最后一个元素; 20 # 没有更多的元素时,抛出StopIteration的错误。 21 #正确的方法是使用for循环,因为generator也是可迭代对象。 22 print('----------------------') 23 for i in b: 24 print(i) 25 print('----------------------') 26 for i in b: 27 print(i)
2、生成器:函数实现
1 #斐波那契函数 2 def fib(max): 3 n,a,b = 0,0,1 4 while n< max: 5 print(b) 6 a,b = b,a+b 7 #等价于 8 # t = (b,a+b) 9 # a = t[0] 10 # b = t[1] 11 n += 1 12 return '----done------' 13 14 print('fib函数'.center(50,'-')) 15 print(fib(10)) 16 17 print('fib generator'.center(50,'-')) 18 #定义generator的另一种方法:如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator。 19 def g_fib(max): 20 n,a,b = 0,0,1 21 while n< max: 22 yield b 23 a,b = b,a+b 24 #等价于 25 # t = (b,a+b) 26 # a = t[0] 27 # b = t[1] 28 n += 1 29 return '----done------' 30 #generator和函数的执行流程不一样。 31 # 函数是顺序执行,遇到return语句或者最后一行函数语句就返回。 32 # generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。 33 g = g_fib(10) 34 print(g) 35 36 print(g.__next__()) 37 print(g.__next__()) 38 print('走个神,干点别的事。。。') 39 print(g.__next__()) 40 #基本上从来不会用next()来获取下一个返回值,而是直接使用for循环来迭代: 41 print('for 循环迭代。。。。。') 42 for i in g: 43 print(i) 44 45 #但是用for循环调用generator时,拿不到generator的return语句的返回值。 46 # 如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value中: 47 print('fib generator 获取返回值'.center(50,'-')) 48 g1 = g_fib(10) 49 while True: 50 try: 51 print(g1.__next__(),', ',end= '') 52 except StopIteration as e: 53 print('\nGenerator return value:', e.value) 54 break
3、生成器:牛逼的作用,实现协程并行运算
1 #通过生成器实现协程并行运算 2 #生产者消费者模型 3 import time 4 def consumer(name): 5 print("%s 准备吃包子啦!" %name) 6 while True: 7 baozi = yield 8 9 print("包子[%s]来了,被[%s]吃了!" %(baozi,name)) 10 11 12 def producer(name): 13 c = consumer('A') #创建生成器 14 c2 = consumer('B') 15 c.__next__() #第一次走到yield 16 c2.__next__() 17 print("老子开始准备做包子啦!") 18 for i in range(10): 19 time.sleep(1) 20 print("做了2个包子!") 21 c.send(i) 22 c2.send(i) 23 24 25 # c = consumer('cz') 26 # c.__next__() 27 # b1 = '韭菜包子' 28 # c.send(b1) 29 # c.__next__() 30 31 producer("alex")
三、迭代器
1、迭代器与可迭代对象
可迭代对象(Iterable):可以直接作用于for循环的对象统称为可迭代对象;
例如:一类是集合数据类型,如list、tuple、dict、set、str等;
一类是generator,包括生成器和带yield的generator function。
1 from collections import Iterable 2 print(isinstance([],Iterable)) 3 print(isinstance(range(10), Iterable))
迭代器对象(Iterator):可以被next()函数调用并不断返回下一个值的对象称为迭代器;
1 #可以使用isinstance()判断一个对象是否是Iterator对象: 2 from collections import Iterator 3 print(isinstance((x for x in range(10)), Iterator)) #True 4 print(isinstance(range(10), Iterator)) #False
2、可迭代对象 —> 迭代器
1 # 集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。 2 3 #示例: 4 for x in [1, 2, 3, 4, 5]: 5 pass 6 7 # 首先获得Iterator对象: 8 it = iter([1, 2, 3, 4, 5]) 9 # 循环: 10 while True: 11 try: 12 # 获得下一个值: 13 x = next(it) 14 print(x) 15 except StopIteration: 16 # 遇到StopIteration就退出循环 17 break