迭代器、生成器、装饰器(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

原文地址:https://www.cnblogs.com/MUMO/p/5761855.html