python迭代器,生成器,装饰器
一、迭代器
迭代器从表面上看是一个数据流对象或容器,当使用其中的数据时,每次从数据流中取一个数据,直到数据被取完,而且数据不会被重复使用
__iter__():
__next__():
"__iter__()"方法返回对象本身,它是for语句使用迭代器的要求
"__next__()"方法用于返回容器中下一个元素或数据,当容器中的数据用尽时,应该引发StopIteration异常
任何一个类,只要它实现了或具有这两个方法,就可以称其为迭代器,也可以说是迭代的。在使用它作为迭代器时,就可以用for来遍历(迭代)它,示例代码如下
for item in iterator:
pass
每个循环中,for语句都会从迭代器的序列中取一个数据,并赋值给item,供循环内使用或处理。从形式上完全与遍历元组,列表,字符串,字典等序列一样class MyIterator: #自定义类迭代器MyIterato def __init__(self,x=2,xmax=100): #定义构造方法,初始化实例属性
class MyIterator: #自定义类迭代器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 #一定要raise或asrest等引 StopIteration 错误 else: raise StopIteration if __name__ =='__main__': myiter = MyIterator() #实例化迭代器MyIterator for i in myiter: #遍历并输出值 print('迭代的数据元素为:',i) #执行结果 迭代的数据元素为: 4 迭代的数据元素为: 8 迭代的数据元素为: 16 迭代的数据元素为: 32 迭代的数据元素为: 64
【代码说明】
从代码中可以看出,如果需要产生很大范围的数的序列,采用列表或元组等进行一次性生成,则必须会占据大量
的内存空间,对系统有很大的“杀伤力”。而使用了迭代器,则可以每次调用时生成一个,显然可以节约大量的内存空间。
二、生成器
生成器对象是通过使用yield关键字定义的函数,因此,生成器也是一个函数。生成器用于生成一个值的序列,以便在迭代中使用
yield关键字,先返回一个值,然后停止,在下一次运行的时候,在停止的这个位置继续运行
return 是函数返回后,直接退出函数,yield包含return功能,但不退出函数,下次直接在yield下一句语句执行
def myYield(n): #定义一个生成器(函数) while n < 5: print('start') yield n #yield这一步就开始返回n的值了,在进入下一步从print('one...')开始执行 print('one...') n += 1 if __name__ == '__main__': for i in myYield(1): #for循环遍历生成器 print('遍历得到的值:',i) print() my_yield = myYield(0) #生成一个生成对象 print('已经实例化生成器对象') print(my_yield.__next__()) #手工调用其特殊方法,获取序列中一个值 print(my_yield.__next__()) #第二次手工调用,继续输出yield之后的输出 #执行结果 start 遍历得到的值: 1 one... start 遍历得到的值: 2 one... start 遍历得到的值: 3 one... start 遍历得到的值: 4 one... 已经实例化生成器对象 start 0 one... start 1
【代码说明】
生成器中包含yield语句,可以用for直接遍历,也可以手工调用其__next__()方法进行遍历
yield语句是生成器中的关键语句,生成器在实例化时并不会立即执行,而是等待调用其__next__()方法才开始运行,并且当程序运行完yield语句后就会 “hold”,即保持其当前状态且停止运行,等待下一次遍历才恢复运行
生成器与协程
运用send()方法来重置生成器的生成序列,可以发送数字字符串等
def consumer(): #定义一个消费者模型(生成器协程) print('等待接收处理任务。。。') while True: data = (yield) print('收到任务:',data) #模拟接受并处理任务 #此处可以调用函数来完成任务 def producer(): #定义一个生产者模型 c =consumer() c.__next__() for i in range(3): print('发送一个任务。。。','任务%d' %i) c.send(1) #发送数字“1” c.send('任务%d' %i) #发送字符串 if __name__ == '__main__': producer() #调用函数producer #执行结果 等待接收处理任务。。。 发送一个任务。。。 任务0 收到任务: 1 收到任务: 任务0 发送一个任务。。。 任务1 收到任务: 1 收到任务: 任务1 发送一个任务。。。 任务2 收到任务: 1 收到任务: 任务2
【代码说明】
代码中通过定义的两个函数分别代表生成者和消费者模型,而其中的消费者模型实际是一个生成器。在生成者模型函数中每个循环模拟发送一个任务给消费者模型(生成器),而生成器则可以调用相关函数来处理任务,这就是运用yield语句的“hold”性质来完成这一项任务
装饰器:
装饰器是一种增加函数或类的功能的简单方法,它可以快速地给不同的函数或类插入相同的功能,从本质上说,它是一种代码实现方式。
实例:装饰函数
def abc(fun): #定义一个装饰abc def wrapper(*args,**kwargs): #定义包装器函数 print('start...') fun(*args,**kwargs) #调用被装饰器 print('end...') return wrapper #返回包装器函数 @abc #装饰函数语句 def demo_decoration(x): #定义普通函数,被装饰器装饰 a = [] for i in range(x): a.append(i) print(a) @abc def hello(name): #定义普通函数,被装饰器装饰 print('Hello',name) if __name__ == '__main__': demo_decoration(5) #调用被装饰器装饰的函数 print() hello('XP') #调用被装饰器装饰的函数 #执行结果 start... [0, 1, 2, 3, 4] end... start... Hello XP end...
【代码说明】
代码中首先定义了一个装饰器函数(abc),它带有一个可以使用函数对象的参数,接着定义了两个被装饰器装饰的普通函数(demo_decoration,hello)。最后对被装饰器的函数进行调用。由此可见,调用被装饰器的函数,与调用普通函数没有任何区别,而在装饰器定义的内部,很明显又定义了一个内嵌的函数(wrapper),在这个内嵌的函数中执行了其他的一些语句,也调用了被装饰的函数。最后返回了这个内嵌的函数,代替了被装饰的函数,从而完成了装饰器的功能。
实例:装饰类
装饰器不仅可以装饰函数,也可以装饰类。定义装饰类的装饰器,采用的方法是:定义内嵌类的函数,并返回新类
def abc(myclass): #定义装饰器 class InnerClass: #定义嵌套的类 def __init__(self,z=0): self.z = 0 self.wrapper = myclass() #实例化被装饰的类 def position(self): self.wrapper.position1() #调用被装饰类的方法 print('z axis:',self.z) return InnerClass #返回新定义的类 @abc #应用装饰器 class coordination: #定义普通的类 def __init__(self,x=0,y=0): self.x = x self.y = y def position1(self): print('x axis:',self.x) print('y axis:',self.y) if __name__ == '__main__': coor = coordination() #实例化被装饰的类 coor.position() #调用类中的方法position() #执行结果 x axis: 0 y axis: 0 z axis: 0
【代码说明】
代码中首先定义了一个能够装饰类的装饰器abc,在其中定义了一个内嵌类InnerClass,用于代替被装饰的类,并放回新的内嵌类。而在实例化普通类时,得到的就是被装饰器装饰过后的类