定义:本质是函数,(装饰其他函数)就是为其他函数添加附加功能
原则: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 timedef 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))
-------------------输出结果------------------------
-------------------输出结果-------------------------024681012141618
生成器 只有在调用时才会生成相应的数据
只记住当前位置
只有一个__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 &#61; b, a&#43;b
6 n &#43;&#61; 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 &#61; 0,0,1
3 while (n <max):
4 yield b
5 a,b &#61; b, a&#43;b
6 n &#43;&#61; 1
7 f &#61; 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 &#61; yield
5 print("包子[%s]来了&#xff0c;被[%s]吃了" %(baozi,name))
6
7
8 c &#61; consumer("wsy")
9 c.__next__()
10
11 def producer(name):
12 c &#61; consumer(&#39;猫&#39;)
13 c2 &#61; consumer(&#39;狗&#39;)
14 c.__next__()
15 c2.__next__()
16 print("开始吃")
17 for i in range(10):
18 time.sleep(1)
19 print("做了1个包子&#xff0c;分两半")
20 c.send(i)
21 c2.send(i)
22 producer("wsy")
23 ---------------------------结果------------------------
24 开始吃
25 做了1个包子&#xff0c;分两半
26 包子[0]来了&#xff0c;被[猫]吃了
27 包子[0]来了&#xff0c;被[狗]吃了
28 做了1个包子&#xff0c;分两半
29 包子[1]来了&#xff0c;被[猫]吃了
30 包子[1]来了&#xff0c;被[狗]吃了
31 做了1个包子&#xff0c;分两半
32 包子[2]来了&#xff0c;被[猫]吃了
33 包子[2]来了&#xff0c;被[狗]吃了
34 做了1个包子&#xff0c;分两半
35 包子[3]来了&#xff0c;被[猫]吃了
36 包子[3]来了&#xff0c;被[狗]吃了
37 做了1个包子&#xff0c;分两半
38 包子[4]来了&#xff0c;被[猫]吃了
39 包子[4]来了&#xff0c;被[狗]吃了
40 做了1个包子&#xff0c;分两半
41 包子[5]来了&#xff0c;被[猫]吃了
42 包子[5]来了&#xff0c;被[狗]吃了
43 做了1个包子&#xff0c;分两半
44 包子[6]来了&#xff0c;被[猫]吃了
45 包子[6]来了&#xff0c;被[狗]吃了
46 做了1个包子&#xff0c;分两半
47 包子[7]来了&#xff0c;被[猫]吃了
48 包子[7]来了&#xff0c;被[狗]吃了
49 做了1个包子&#xff0c;分两半
50 包子[8]来了&#xff0c;被[猫]吃了
51 包子[8]来了&#xff0c;被[狗]吃了
52 做了1个包子&#xff0c;分两半
53 包子[9]来了&#xff0c;被[猫]吃了
54 包子[9]来了&#xff0c;被[狗]吃了
我们已经知道&#xff0c;可以直接作用于for循环的数据类型有一下几种&#xff1a;
1.集合数据类型&#xff0c;如list&#xff0c;tuple&#xff0c;dict&#xff0c;set&#xff0c;str等
2.生成器&#xff0c;包括生成器和带yield的generator function
这些可以直接作用于for循环的对象统称为可迭代对象&#xff1a;Iterable
可以使用isinstance()判断一个对象是否是Iterable对象&#xff1a;
1 命令行
2 >>> from collections import Iterable
3 >>> isinstance([],Iterable)
4 True
5 >>> isinstance({},Iterable)
6 True
7 >>> isinstance(&#39;abc&#39;,Iterable)
8 True
9 >>> isinstance((x for x in range(10)),Iterable)
10 True
11 >>> isinstance(100,Iterable)
12 False
而生成器不但可以作用于for循环&#xff0c;还可以被next()函数不断调用并返回下一个值&#xff0c;知道最后抛出StopIteration错误表示无法继续返回下一个值了。
*可以被next()函数调用并不断返回下一个值得对象成为迭代器&#xff1a;Iterator
可以使用isinstance()判断一个对象是否是Iterator对象&#xff1a;
#结论&#xff1a;生成器一定是迭代器 迭代器不一定是生成器
生成器都是Iterator&#xff08;迭代器&#xff09;对象&#xff0c;但list&#xff0c;dict&#xff0c;str虽然是iterable&#xff08;可迭代&#xff09;却不是Iterator&#xff08;迭代器&#xff09;
把list&#xff0c;dict&#xff0c;str等Iterable变成Iterator可以使用iter()函数&#xff1a;
1 >>> a
2 [1, 2, 3]
3 >>> iter(a)
4
5 >>> b &#61; iter(a)
6 >>> b.__next__()
7 1
8 >>> b.__next__()
9 2
10 >>> b.__next__()
只要有next()函数 一定是迭代器