python -- 迭代器和装饰器

迭代器和装饰器在python中的使用十分常见,下面是个人对迭代器和装饰器的理解

迭代器

  1、迭代器 iter 的特点:

    (1).访问者不需要关心迭代器的内部结构,仅需要通过__next__()方法不断去取下一个内容
    (2).不能随机访问集合(不是set,只是一些元素的聚集体)中的某个值,只能从头到尾依次访问
    (3).访问到一半时不能后退(过去的就过去了,不能回头)
    (4).便于循环比较大的数据集合,节省内存(每次需要了指定数据时,才把该读取到内存中,eg:迭代文件时,内存中每一时刻都只有文件的一行)

1 a = iter(['root','admin','python','ruby' ])    #生成一个迭代器
2 print(a.__next__())   
3 print(a.__next__())      #只有一个__next__() 方法
4 print('waitting!')    #在第二代的过程中,能停下来做其他的事
5 print(a.__next__())     
6 print(a.__next__())
7 #print(a.__next__())    #报错 超出迭代器范围

  常见迭代器使用:
    读文件时:
      with open('a*.txt','r+') as f:
        for line in f:
        ...
    这里的for i in f:就是用的迭代器,避免依次把文件内容全部读取到内存中,节省内存。

在介绍迭代器时,还有个概念要明白,何为生成器

  生成器 generator
  定义: 一个函数调用时返回一个迭代器,那么这个函数就叫做生成器,如果函数中包含了yield语法,那么这个函数就会变成一个生成器(保存函数的中断状态)

 1 >>> 
 2 >>> def test_yeild(n):
 3     while n > 0:
 4         n -= 2
 5         yield 10
 6         print('注意何时打印这句话...')
 7 
 8         
 9 >>> t = test_yeild(12)      # 与普通函数不同,这里只是生成一个迭代器,不会跳到‘函数体’里面去(执行函数体),而是等待迭代器的__next__()方法
10 >>> t.__next__()
11 10                # 返回yield后面的值,并在执行完yield后 暂停程序 ,等待下一次__next__(),然后接着从暂停的地方开始运行
12 >>> t.__next__()          
13 注意何时打印这句话...
14 10
15 >>> t.__next__()
16 注意何时打印这句话...
17 10
18 >>> t.__next__()
19 注意何时打印这句话...
20 10
21 >>> t.__next__()
22 注意何时打印这句话...
23 10
24 >>> t.__next__()
25 注意何时打印这句话...
26 10
27 >>> t.__next__()
28 注意何时打印这句话...
29 Traceback (most recent call last):
30   File "<pyshell#162>", line 1, in <module>
31     t.__next__()
32 StopIteration
33 >>> 

yield 可以返回一个值,也可以接收一个值,给yield传值用send()

看下面例子,用yield做了个简单的异步操作:

 1 import time
 2 
 3 def consumer(name):
 4     print("%s 准备吃包子啦!" %name)
 5     while 1:
 6         baozi = yield
 7         print("包子[%s]来了,被[%s]吃了" %(baozi,name))
 8         
 9 def producer(name):
10     c = consumer('A')
11     c2 = consumer('B')
12     c.__next__()
13     c2.__next__()
14     print("%s开始准备做包子啦!" %name)
15     for i in range(3):
16         time.sleep(1)        #执行时为了更清楚的看到过程
17         print("做了2个包子")
18         c.send(i)
19         c2.send(i)
20               
22 producer('root')

A 准备吃包子啦!
B 准备吃包子啦!
root开始准备做包子啦!
做了2个包子
包子[0]来了,被[A]吃了
包子[0]来了,被[B]吃了
做了2个包子
包子[1]来了,被[A]吃了
包子[1]来了,被[B]吃了
做了2个包子
包子[2]来了,被[A]吃了
包子[2]来了,被[B]吃了

  

 1 def account(money):
 2     while money > 0:
 3         out_money = yield 
 4         money -= out_money
 5         #yield 300
 6         print('又来取钱了!取了%s' %out_money)
 7         
 8 atm = account(1500)
 9 atm.__next__()
10 for i in range(5):
11     atm.send(300)
12     #在第一次用__next__()方法启动迭代器后,每次调用迭代器,就会自动执行__next__()方法
13     

装饰器

  装饰器基本功能:对已有函数进行扩展

  (个人初步理解,可能错误)
  装饰器执行过程:
    1.在调用被装饰器装饰的函数时,先把被装饰器装饰的函数(装饰器下一行代码中函数)的函数名传递给装饰器从内到外第二层定义的函数
    2.把被装饰器装饰的函数的实参传递给装饰器最内层函数
    3.在装饰器内部实现被装饰器装饰的函数的调用

 简单装饰器:

 1 def login(func):
 2     def inner(*args,**kwargs):
 3         print("我是做身份验证的,验证成功才能调用函数")
 4         print(args,kwargs)
 5         func(*args,**kwargs)
 6         #return func(*args,**kwargs)
 7     return inner
 9     #若传进来的是函数名,那么没有执行'()'的话,即是函数的内存地址
10 
11 #@login    #(装饰器)程序一执行,就会调用装饰器的函数
12 def home(name):
13     print("welcome [%s] vidited the home page" %name)
14 
15 @login   #@符号的作用: 相当于执行 tv = login(tv) 
16 #def tv(name,passwd=123):
17 def tv(*args,**kwargs):
18     print("welcome [%s] vidited the tv page" %args )
19     #若这里有返回值,则仅需要在inner里面返回函数结果
20 #@login
21 def movices(name):
22     print("welcome [%s] vidited the movices page" %name)
23     
24 tv('root')
25 tv('xtsec',passwd=123)

复杂装饰器:

 1 '''
 2 调用装饰器时(eg:@login(f1,f2)),传递多个参数的装饰器(三层装饰器)
 3 '''
 4 def before():
 5     print("执行要装饰的函数之前执行")
 6 
 7 def affter():
 8     print("执行要装饰的函数之后执行")      #没有return的函数默认返回None
 9 
10 def test_ge(before1,affter1):
11     def login(func):
12         def inner(*args,**kwargs):
13             result_before = before1()
14             if(result_before != None):     
15                 return '执行before条件未成功!'    #这里运行就表示before函数没有正确运行结束,所以表示验证没通过
16             ret = func(*args,**kwargs)
17             if(ret != None):
18                 return '执行被修饰函数不成功!'    #若前面验证通过,且装饰器正确执行,到这里整个装饰器运行结束
19             result_afftr = affter1()
20             if(result_afftr != None):
21                 return '执行时不满足要求!'     #若前面装饰器修身的函数没正确运行,就会到这里,常用来返回错误信息
22             return ret
23         return inner
24     return login
25 
26 def home(name):
27     print("welcome [%s] vidited the home page" %name)
28 
29 '''
30 接下来这一行有三个操作:
31 1.调用函数 test_ge(before, affter)
32 2.@login   login为调用test_ge(before, affter)的返回值
33 3.新tv = inner    login()的返回值
34 '''
35 @test_ge(before, affter)   
36 def tv(*args,**kwargs):
37     print("welcome [%s] vidited the tv page" %args )
38     return 1
39 
40 def movices(name):
41     print("welcome [%s] vidited the movices page" %name)
42 
43 
44 tv('root',passwd='admin')   
45     #在这里执行tv()时,事实上时执行新的tv(),即是inner()
46 a = before()
47 print(type(a),a)
48 if a == None:
49     print('110')

在日常使用中,一般就用普通的装饰器,复杂度这个最好明白运行原理即过程

原文地址:https://www.cnblogs.com/xtsec/p/6682331.html