迭代器、生成器、装饰器(9)
第9章 迭代器、生成器、装饰器
迭代器:迭代器是一个数据流对象和容器,当使用其中的数据时,每次从数据流中取一个数据,直到数据被取完,而且数据不会被重复使用。
从代码角度将讲:迭代器是实现了迭代器协议方法的对象或类。
迭代器
协议方法:
__iter__() ,返回对象本身,是for语句使用迭代器的要求
__next__() ,返回容器中下一个元素或数据,当容器中的数据用尽时,应该引发StopIterator异常
可以使用for循环遍历
for item in iterator
迭代器的优点:节约内存
自定义迭代器:实现协议方法
class MyIterator:
def __init__(self,x=2,xmax=100):
self.__mul,self.__x=x,x
self.__xmax=xmax
def __iter__(self):
return self
def __next__(self):
if self.__mul and self.__x!=1:
self.__mul*=self.__x
if self.__mul<=self.__xmax:
return self.__mul
else:
raise StopIteration
else:
raise StopIteration
if __name__=='__main__':
myiter=MyIterator()
for i in myiter:
print('迭代的数据元素为:',i)
内置迭代器工具:
1.内建迭代函数iter()
iter(iterable) #参数为可迭代的类型,包括序列
iter(callable,sentinel) #callable是可调用类型,一般为函数;sentinel为"哨兵",即当callable调用的返回值等于第二个参数的值时,迭代或遍历停止
例子:
class Counter:
def __init__(self,x=0):
self.x=x
counter=Counter()
def used_iter():
counter.x+=2
return counter.x
for i in iter(used_iter,8):
print('本次遍历的值:',i)
2.itertools模块中常用工具函数
count(start) #start开始,计数迭代
cycle(seq) #循环迭代序列seq
以上两中无限迭代器使用时,必须有迭代退出的条件,否则会有死循环
repeat(elem[,n]) #循环迭代elem,n为迭代次数
chain(p,q,....) #将p,q连接起来迭代,就像从一个序列中迭代
dropwhile(pred,seq) #当pred对序列元素处理结果为假时开始迭代seq后所有值
takewhile(pred,seq) #取值与dropwhile相反
filterfalse(pred,seq) #当pred处理为假的元素
tee(it,b) #将it重复n次进行迭代(嵌套for循环)
permutations(p,r) #迭代序列中r个元素的排列
combinations(p,r) #迭代序列中r个元素的组合
生成器
使用生成器,可以生成一个值的序列用于迭代,并且这个值的序列不是一次生成的,而是使用一个,再生成一个,可以节约大量内存
生成对象可以直接被for遍历,也可以手工进行遍历
例子:
def myYield(n):
while n>0:
print("开始生成:....")
yield n
print("完成一次....")
n-=1
if __name__=='__main__':
for i in myYield(4):
print("遍历得到的值:",i)
print()
my_yield=myYield(3)
print('已经实例化生成器对象')
my_yield.__next__()
print('第二次调用__next__()方法:')
my_yield.__next__() #__next__()函数的返回值是关键字yield后的n的值
生成器在实例化时并不会立即执行,而是等待调用其__next__()才开始运行。
当程序运行完yield语句后就会“hold住”,即保持其当前状态且停止运行
等待下一次遍历时才恢复运行,生成器的恢复运行是从yield语句之后开始运行的
yield语句不仅可以使函数成为生成器和返回值,还可以接受调用者传来的数值。
例:
def myYield(n):
while n>0:
rcv=yield n
n-=1
if rcv is not None:
n=rcv
if __name__=='__main__':
my_yield=myYield(3)
print(my_yield.__next__())
print(my_yield.__next__())
print('传给生成器一个值,重新初始化生成器。')
print(my_yield.send(10))
print(my_yield.__next__())
生成器的另一种表达式:a=i for i in range(5) #推导最外层的括号去掉
list(a) 把a这个生成器对象转化为列表
注:如果生成器生成的序列是无限的或大量的序列,不可以将其转换为列表,否则会导致死机或大量消耗内存
通过生成器实现协程
例:生产者与消费者编程模型
def consumer():
print('等待接受处理任务...')
while True:
data=(yield)
print('收到任务:',data)
def producer():
c=consumer()
c.__next__() #第一次调用生成器时不能传递给生成器None以外的值,否则会引发错误
for i in range(3)
print('发送一个任务....','任务%d'%i)
c.send('任务%d'%i)
if __name__=='__main__':
producer()
__next__()和send()在一定意义上作用是相似的,区别是send()可以传递yield表达式的值进去,而__next__()不能传递特定的值,只能传递None进去。因此,我们可以看做c.__next__() 和 c.send(None) 作用是一样的。
装饰器
装饰器是一种增加函数或类功能的简单方法,可以快速地给不同的函数或类插入相同的功能
使用形式:
@disp_run_time
def decorated_fun():
pass
或嵌套装饰
@abc
@disp_run_time
def decorated_fun():
pass
调用形式:
decorated_fun()
定义装饰器:
def demo_decorater(fun): #定义装饰器函数
def new_fun(*args,**kwargs): #新定义包装器函数
pass
fun(*args,**kwargs) #包装器函数中调用被装饰的函数
pass
return new_fun #返回包装器函数
装饰器也是可以带参数的:
def abc(action):
def mabc(fun):
def wrapper(*args,**kwargs):
print('开始运行....',action)
fun(*args,**kwargs)
print('运行结束....',action)
return wrapper
return mabc
定义装饰类的装饰器:定义内嵌类的函数,并返回新类
例:
def abc(myclass):
class InnerClass:
def __init__(self,z=0):
self.z=z
self.wrapper=myclass()
def position(self):
self.wrapper.position()
print('z axis:',self.z)
return InnerClass
@abc
class coordination:
def __init__(self,x=0,y=0):
self.x=x
self.y=y
def position(self):
print('x axis:',self.x)
print('y axis:',self.y)
if __name__=='__main__':
coor=coordination()
coor.position()
输出结果:
x axis: 0
y axis: 0
z axis: 0