首页 > 代码库 > python -- 迭代器和装饰器
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‘)
在日常使用中,一般就用普通的装饰器,复杂度这个最好明白运行原理即过程
python -- 迭代器和装饰器