代码改变世界

python模块学习:Iterators和Generators

2017-07-04 14:29  很大很老实  阅读(652)  评论(0编辑  收藏  举报

转自:http://www.cnblogs.com/zhbzz2007/p/6102695.html

1 迭代器:

迭代器,允许你在一个容器上进行迭代的对象。

python的迭代器主要是通过__iter__和__next__两个方法来实现。

__iter__,要求你的容器支持迭代,返回对象本身。如果想创建一个迭代器对象,还需要实现__next__方法,这个返回下一个对象。

为了对这些概念更加清晰,让我们回顾下面的两个定义:

  • 可迭代对象(iterable),只定义了__iter__方法;
  • 迭代器(iterator),定义了__iter__和__next__两个方法,__iter__返回迭代器本身,__next__方法返回下一个元素

所有函数名中有双下划线的方法,都很神奇,你不需要直接调用__iter__或者__next__。你可以使用for循环或者转换为列表,Python就会自动替你调用这些方法。当然你或许还是想调用它们,那么你可以使用Python内置的函数iter和next方法。

python3中,list是支持迭代的,但不是迭代器对象。因为,它不支持__next__

看代码:

a=[1,2,3,4,5]
next(a)

错误信息是:

C:\Python35\python.exe C:/Users/wcf/PycharmProjects/Algorithms/wcf.py
Traceback (most recent call last):
  File "C:/Users/wcf/PycharmProjects/Algorithms/wcf.py", line 3, in <module>
    next(a)
TypeError: 'list' object is not an iterator

Process finished with exit code 1

通过iter内建函数,可以把他转变成迭代器:

a=[1,2,3,4,5]

for item in iter(a):
    print(item)

当你使用循环来遍历一个迭代器,你就不需要调用next方法,你也无需担心会收到StopIteration异常信息。

比如:

a=[1,2,3,4,5]

a_iter=iter(a)
next(a_iter)
next(a_iter)
next(a_iter)
next(a_iter)
next(a_iter)
next(a_iter)
next(a_iter)

会出错的:

C:\Python35\python.exe C:/Users/wcf/PycharmProjects/Algorithms/wcf.py
Traceback (most recent call last):
  File "C:/Users/wcf/PycharmProjects/Algorithms/wcf.py", line 10, in <module>
    next(a_iter)
StopIteration

Process finished with exit code 1

 

2.创建属于自己的迭代器,很简单,实现几个方法就可以:

class my_iterator():
    def __init__(self,letters):
        self.letters=letters
        self.position=0

    def __iter__(self):
        return self

    def __next__(self):
        if self.position>=len(self.letters):
            raise StopIteration
        letter=self.letters[self.position]
        self.position+=1
        return letter

if __name__=="__main__":
    i=my_iterator('abcd')
    for item in i:
        print(item)

 

3.生成器

一个普通的Python函数经常返回一个值,无论它是列表、整数还是其他对象。但是如果你想调用一个函数,这个函数能否产生一系列值呢?这个就是生成器诞生的原因。生成器的工作机制是保存它所停止(或者说它已经产生)的位置,然后给主调函数返回一个值。不是返回一个调用函数的执行,生成器仅仅返回一个临时的控制返回。为了完成这个功能,生成器函数需要使用Python的 yield 语句。

def double_generator():
    number=2
    while True:
        yield number
        number+=2


doubler =double_generator()

print(next(doubler))
print(next(doubler))
print(next(doubler))
print(next(doubler))

输出是:

C:\Python35\python.exe C:/Users/wcf/PycharmProjects/Algorithms/wcf.py
2
4
6
8

Process finished with exit code 0

实际上,上文,也有一个next方法。

而下面的例子,就是没有:

def double_generator():
        yield 'wcf1'
        yield 'wcf2'
        yield 'wcf3'


doubler =double_generator()

print(next(doubler))
print(next(doubler))
print(next(doubler))

输出是:

C:\Python35\python.exe C:/Users/wcf/PycharmProjects/Algorithms/wcf.py
wcf1
wcf2
wcf3

Process finished with exit code 0

同样的,如果是:

def double_generator():
        yield 'wcf1'
        yield 'wcf2'
        yield 'wcf3'


doubler =double_generator()

print(next(doubler))
print(next(doubler))
print(next(doubler))
print(next(doubler))

一样会触发一场:

C:\Python35\python.exe C:/Users/wcf/PycharmProjects/Algorithms/wcf.py
wcf1
Traceback (most recent call last):
wcf2
wcf3
  File "C:/Users/wcf/PycharmProjects/Algorithms/wcf.py", line 12, in <module>
    print(next(doubler))
StopIteration

Process finished with exit code 1

而这样写,就ok:

def double_generator():
        yield 'wcf1'
        yield 'wcf2'
        yield 'wcf3'


doubler =double_generator()

for item in doubler:
    print(item)