python笔记-----装饰器,生成器,迭代器
1.装饰器
定义:本质是函数,(装饰其他函数)就是为其他函数添加附加功能
原则:1.不能修改被装饰的函数的源代码
2.不能修改被装饰的函数的调用方式
实现装饰器的知识储备:
1. 函数即“变量”
2. 高阶函数
a. 把一个函数名当做实参传给另一个函数(在不修改被装饰函数源代码的情况下为期添加功能)
b. 返回值中包含函数名(不修改函数的调用方式)
3. 嵌套函数
4. 高阶函数+嵌套函数=装饰器
1.1 实现简单的装饰器
1 def outer(fun): 2 def warper(): 3 print("outer 1") 4 fun() #相当于把下边两个函数当参数传入进来 5 print("outer 3") 6 return warper 7 8 @outer 9 def test1(): 10 print("test1 2") 11 @outer 12 def test2(): 13 print("test2 2") 14 test1()
15 test2()
-----------------结果----------------- 16 outer 1 17 test1 2 18 outer 3 19 outer 1 20 test2 2 21 outer 3
1.2 装饰器传参
简单难度的传参
1 def outer(fun): 2 def warper(*args,**kwargs): 3 print("加的第一个功能在函数之前") 4 fun(*args,**kwargs) 5 print("加的第二个功能在函数之后") 6 return warper 7 8 @outer 9 def test1(*args,**kwargs): 10 print(args,kwargs) 11 return 12 13 14 test1(123,"waa","yyy",name="wsy",Age=18) 15 ----------------结果---------------------- 16 加的第一个功能在函数之前 17 (123, 'waa', 'yyy') {'name': 'wsy', 'Age': 18} 18 加的第二个功能在函数之后
中等难度的传参
加入time模块记录执行时间
import time def timer(func): def deco(*args,**kwargs): start = time.time() print("装饰器:功能1") func(*args,**kwargs) print("装饰器:功能2") end = time.time() print("func run time is %s" %(end - start)) return deco @timer def test1(): time.sleep(1) print("in the test1") @timer def test2(*args,**kwargs): time.sleep(1) print("in the test1",args,kwargs) test1() test2(1,2,3,4,name="wsy",age=20) --------------------结果------------------------ 装饰器:功能1 in the test1 装饰器:功能2 func run time is 1.0000572204589844 装饰器:功能1 in the test1 (1, 2, 3, 4) {'name': 'wsy', 'age': 20} 装饰器:功能2 func run time is 1.0000572204589844
多重认证 第一个页面认证成功直接进入其他两个页面
1 user,passwd = "wsy","123" 2 def auth(auth_type): 3 print("auth func:",auth_type) 4 def outer_wrapper(func): 5 def wrapper(*args,**kwargs): 6 print("wrapper func args:", *args,**kwargs) 7 if auth_type == "local": # 如果装饰器参数是local 就 8 username = input("Username:").strip() # 输入用户名 9 password = input("Password:").strip() # 输入密码 10 if user == username and passwd == password: # 判断如果正确 11 print("\033[32;1mUser has passwd authentication\033[0m") 12 res = func(*args,**kwargs) #from home 13 print("-------after authenticaion") 14 return res 15 else: 16 exit("\033[31;1mInvalid username or password \033[0m") 17 elif auth_type == "ldap": # 如果装饰器参数是ldap 18 print("hehe") 19 return wrapper 20 return outer_wrapper 21 22 23 def index(): 24 print("welcome to index page") 25 26 @auth(auth_type="local") 27 28 def home(): 29 print("welcome to home page") 30 return "from home" 31 @auth(auth_type="ldap") 32 def bbs(): 33 print("welcome to bbs page") 34 index() 35 print (home()) 36 bbs() 37 -----------------------结果----------------------- 38 auth func: local 39 auth func: ldap 40 welcome to index page 41 wrapper func args: 42 Username:wsy 43 Password:123 44 User has passwd authentication 45 welcome to home page 46 -------after authenticaion 47 from home 48 wrapper func args: 49 hehe
2.生成器
生成器
通过列表生成式,我们可以直接创建一个列表。但是受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量空间,在py中,这种一遍循环一遍计算的机制,称为生成器
终端命令行执行 >>> a = [1,2,3] >>> [i*2 for i in range(10)] -----------------输出结果----------------- [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
终端执行: >>> ( i*2 for i in range(10)) -------------------输出结果------------------------ <generator object <genexpr> at 0x00000000021859E8> >>>b = ( i*2 for i in range(10)) >>> for i in b: ... print(i) -------------------输出结果------------------------- 0 2 4 6 8 10 12 14 16 18
生成器 只有在调用时才会生成相应的数据
只记住当前位置
只有一个__next__()方法
1 a = (i*2 for i in range(100)) 2 print(a.__next__()) 3 print(a.__next__()) 4 print(a.__next__()) 5 print(a.__next__()) 6 ---------------输出结果------------------- 7 0 8 2 9 4 10 6
我们创建了一个generator(生成器)后,基本上永远不会调用next(),而是通过for循环来迭代它,并且不需要关心StopIteration的错误
generator(生成器)非常强大,如果推算的算法比较复杂,用列斯列表生成式的for循环无法实现的时候,还可以用函数来实现
2.1 斐波那契数列
菲波纳契数列,除第一个和第二个数外,任意一个数都可由前两个数相加得到
1 def fib(max): 2 n, a, b = 0, 0, 1 3 while (n < max): 4 print(b) 5 a, b = b, a+b 6 n += 1 7 8 fib(10) 9 --------------------------------------- 10 1 11 1 12 2 13 3 14 5 15 8 16 13 17 21 18 34 19 55
2.2 yield
1 def fib(max): 2 n,a,b = 0,0,1 3 while (n < max): 4 yield b 5 a,b = b, a+b 6 n += 1 7 f = fib(10) 8 for i in range(10): 9 print(f.__next__()) 10 --------------输出结果----------------- 11 1 12 1 13 2 14 3 15 5 16 8 17 13 18 21 19 34 20 55
2.3 yield 实现单线程并行
1 import time 2 def consumer(name): 3 while True: 4 baozi = yield 5 print("包子[%s]来了,被[%s]吃了" %(baozi,name)) 6 7 8 c = consumer("wsy") 9 c.__next__() 10 11 def producer(name): 12 c = consumer('猫') 13 c2 = consumer('狗') 14 c.__next__() 15 c2.__next__() 16 print("开始吃") 17 for i in range(10): 18 time.sleep(1) 19 print("做了1个包子,分两半") 20 c.send(i) 21 c2.send(i) 22 producer("wsy") 23 ---------------------------结果------------------------ 24 开始吃 25 做了1个包子,分两半 26 包子[0]来了,被[猫]吃了 27 包子[0]来了,被[狗]吃了 28 做了1个包子,分两半 29 包子[1]来了,被[猫]吃了 30 包子[1]来了,被[狗]吃了 31 做了1个包子,分两半 32 包子[2]来了,被[猫]吃了 33 包子[2]来了,被[狗]吃了 34 做了1个包子,分两半 35 包子[3]来了,被[猫]吃了 36 包子[3]来了,被[狗]吃了 37 做了1个包子,分两半 38 包子[4]来了,被[猫]吃了 39 包子[4]来了,被[狗]吃了 40 做了1个包子,分两半 41 包子[5]来了,被[猫]吃了 42 包子[5]来了,被[狗]吃了 43 做了1个包子,分两半 44 包子[6]来了,被[猫]吃了 45 包子[6]来了,被[狗]吃了 46 做了1个包子,分两半 47 包子[7]来了,被[猫]吃了 48 包子[7]来了,被[狗]吃了 49 做了1个包子,分两半 50 包子[8]来了,被[猫]吃了 51 包子[8]来了,被[狗]吃了 52 做了1个包子,分两半 53 包子[9]来了,被[猫]吃了 54 包子[9]来了,被[狗]吃了
3.迭代器
我们已经知道,可以直接作用于for循环的数据类型有一下几种:
1.集合数据类型,如list,tuple,dict,set,str等
2.生成器,包括生成器和带yield的generator function
这些可以直接作用于for循环的对象统称为可迭代对象:Iterable
可以使用isinstance()判断一个对象是否是Iterable对象:
1 命令行 2 >>> from collections import Iterable 3 >>> isinstance([],Iterable) 4 True 5 >>> isinstance({},Iterable) 6 True 7 >>> isinstance('abc',Iterable) 8 True 9 >>> isinstance((x for x in range(10)),Iterable) 10 True 11 >>> isinstance(100,Iterable) 12 False
而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,知道最后抛出StopIteration错误表示无法继续返回下一个值了。
*可以被next()函数调用并不断返回下一个值得对象成为迭代器:Iterator
可以使用isinstance()判断一个对象是否是Iterator对象:
#结论:生成器一定是迭代器 迭代器不一定是生成器
生成器都是Iterator(迭代器)对象,但list,dict,str虽然是iterable(可迭代)却不是Iterator(迭代器)
把list,dict,str等Iterable变成Iterator可以使用iter()函数:
1 >>> a 2 [1, 2, 3] 3 >>> iter(a) 4 <list_iterator object at 0x0000000002150898> 5 >>> b = iter(a) 6 >>> b.__next__() 7 1 8 >>> b.__next__() 9 2 10 >>> b.__next__()
只要有next()函数 一定是迭代器
上一篇: 王恩东:模块化数据中心是云计算的基石