python笔记-----装饰器,生成器,迭代器

1.装饰器

定义:本质是函数,(装饰其他函数)就是为其他函数添加附加功能

原则:1.不能修改被装饰的函数的源代码

   2.不能修改被装饰的函数的调用方式

实现装饰器的知识储备:

  1.      函数即“变量”

  2.      高阶函数

           a.      把一个函数名当做实参传给另一个函数(在不修改被装饰函数源代码的情况下为期添加功能)

           b.      返回值中包含函数名(不修改函数的调用方式)

  3.      嵌套函数

  4.      高阶函数+嵌套函数=装饰器

扫描二维码关注公众号,回复: 277049 查看本文章

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
range

生成器 只有在调用时才会生成相应的数据       

只记住当前位置

只有一个__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
判断是否为iterable对象

而生成器不但可以作用于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()函数 一定是迭代器

 

猜你喜欢

转载自www.cnblogs.com/wsy1030/p/9015817.html