python 迭代器与生成器

一 迭代器

  可迭代对象:Iterable,例如,ist,str,tuple,dict,set,range(100)。

    具有__iter__方法的叫做可迭代对象。

  迭代器:Iterator,例如,文件句柄。

    具有__next__,__iter__方法的叫做迭代器。

    迭代器调用__iter__()方法还是自身。  

  可迭代对象与迭代器的关系:

    可迭代对象调用了__iter__()方法变成迭代器。

  2 判断是否是可迭代对象,迭代器的方法。

    1 可迭代对象有__iter__方法,没有__next__方法

     迭代器有__iter__ __next__方法

    2 from collections import Iterable/Iteration  

       isinstance()方法

  3 for循环的本质

    for循环可以遍历一个可迭代对象,也可以遍历一个迭代器。

    当遍历一个可迭代对象时,会自动调用其__iter__()方法,变为一个迭代器。然后调用__next__()方法。遇到StopIteration终止。

  4 迭代器取值与索引取值的对照

    迭代器的缺点:不能定点取值。

           不能往回取值。

    迭代器的优点:惰性计算,节省内存。

             可以遍历字典,集合取值。这点是索引无法做到的。无序且不知道有哪些key值。

二 生成器 Generator

  生成器本质上是迭代器。  

  生成器是用户写出来的。

  1 生成器的分类

    带有yield关键字的生成器函数

    由生成器表达式生成的生成器 

  2 生成器函数

    带有yield关键字的函数叫做生成器函数。

    与普通函数的不同之处:调用生成器函数返回来是生成器。

    yield关键字:  

      与return相同的部分:

      与rerurn不同的部分:

  

三 生成器的应用

  生成器可以模仿管道的概念,借助生成器,可以一直往外传值。

  也可以用send方法给生成器传值。

def foo():
    money=0
    day=0
    average=0
    while True:
        value=yield average
        money+=value
        day+=1
        average=money/day
g=foo()

print(g.__next__())
print(g.send(200))

  一些想法:

  想用生成器,首先是要定义函数,函数体内有yield关键字。

  生成器一般与循环配合的使用。

  生成器通过yield向外传值。也可以用send往内传值。

四    egon课上讲的例子。

  表达式形式的生成器到底有什么用。 拿到生成器,从外边给yield传值。  

  注意:返回来看,send方法调用的必是生成器,send括号内的内容给生成器,拿到生成器后面的返回值。send的作用,传值和__next__()

  进阶一,yiled没有返回值。

def init(func):
    def wrapper(*args,**kwargs):
        res=func(*args,**kwargs)
        res.send(None)  #等价于next(res),等价于res.__next__()
        return res
    return wrapper
@init
def eater(name):
    print('{} ready to eat '.format(name))
    while True:
        food=yield
        print('{} is eating {}'.format(name,food))
e=eater('alex')
e.send('dog shit')

  输出:

alex ready to eat 
alex is eating dog shit

  进阶二 yield加上返回值。

def init(func):
    def wrapper(*args,**kwargs):
        res=func(*args,**kwargs)
        res.send(None)  #等价于next(res),等价于res.__next__()
        return res
    return wrapper
@init
def eater(name):
    print('{} ready to eat '.format(name))
    food_list=[]
    while True:
        food=yield food_list
        food_list.append(food)
        print('{} is eating {}'.format(name,food))
e=eater('alex')
print(e.send('dog shit'))
print(e.send('cat shit'))

  输出:

alex ready to eat 
alex is eating dog shit
['dog shit']
alex is eating cat shit
['dog shit', 'cat shit']

  

  进阶三 进阶二中的狗屎,猫屎参数是写死了。可以专门写一个函数,专门make shit。

    分步骤一:

def make_shit(n):
    for i in range(n):         屎是造出来了,但要传值,给人吃呀
        

    分步骤二:

def make_shit(people,n):
    for i in range(n):
        people.send('shit{}'.format(i))             加入一个参数,造完shit后,通过send传值people

    分步骤三:

def init(func):
    def wrapper(*args,**kwargs):
        res=func(*args,**kwargs)
        res.send(None)  #等价于next(res),等价于res.__next__()
        return res
    return wrapper
@init
def eater(name):
    print('{} ready to eat '.format(name))
    food_list=[]
    while True:
        food=yield food_list
        food_list.append(food)
        print('{} is eating {}'.format(name,food))



def make_shit(people,n):
    for i in range(n):
        people.send('shit{}'.format(i))
e = eater('alex')
make_shit(e,5)

  输出:

alex ready to eat 
alex is eating shit0
alex is eating shit1
alex is eating shit2
alex is eating shit3
alex is eating shit4

  make_shit 函数造出shit后不断send给people。

  实际上两个函数协同工作的效果。一个函数不断造值,不断发送给另一个函数。 外面的函数给内部的生成器传值。

  进阶四:

  模拟grep 命令。

原文地址:https://www.cnblogs.com/654321cc/p/7473171.html