python 迭代器 生成器 生成器表达式

来源:互联网 发布:淘宝哪家mcm高仿比较好 编辑:程序博客网 时间:2024/05/01 00:02

迭代器

现在你可能注意到大多数容器对象都可以用 for 遍历:

for element in [1, 2, 3]:    print(element)for element in (1, 2, 3):    print(element)for key in {'one':1, 'two':2}:    print(key)for char in "123":    print(char)for line in open("myfile.txt"):    print(line, end='')

这种形式的访问清晰、简洁、方便。迭代器的用法在 Python 中普遍而且统一。在后台, for 语句在容器对象中调用 iter() 。该函数返回一个定义了 __next__() 方法的迭代器对象,它在容器中逐一访问元素。没有后续的元素时, __next__() 抛出一个 StopIteration 异常通知 for 语句循环结束。你可以是用内建的 next() 函数调用 __next__() 方法;以下是其工作原理的示例:

>>> s = 'abc'>>> it = iter(s)>>> it<iterator object at 0x00A1DB50>>>> next(it)'a'>>> next(it)'b'>>> next(it)'c'>>> next(it)Traceback (most recent call last):  File "<stdin>", line 1, in ?    next(it)StopIteration

了解了迭代器协议的后台机制,就可以很容易的给自己的类添加迭代器行为。定义一个 __iter__() 方法,使其返回一个带有 __next__() 方法的对象。如果这个类已经定义了 __next__() ,那么 __iter__() 只需要返回 self:

class Reverse:    """Iterator for looping over a sequence backwards."""    def __init__(self, data):        self.data = data        self.index = len(data)    def __iter__(self):        return self    def __next__(self):        if self.index == 0:            raise StopIteration        self.index = self.index - 1        return self.data[self.index]
>>> rev = Reverse('spam')>>> iter(rev)<__main__.Reverse object at 0x00A1DB50>>>> for char in rev:...     print(char)...maps

生成器

Generator 是创建迭代器的简单而强大的工具。它们写起来就像是正规的函数,需要返回数据的时候使用 yield 语句。每次 next() 被调用时,生成器回复它脱离的位置(它记忆语句最后一次执行的位置和所有的数据值)。以下示例演示了生成器可以很简单的创建出来:

def reverse(data):    for index in range(len(data)-1, -1, -1):        yield data[index]
>>> for char in reverse('golf'):...     print(char)...flog

前一节中描述了基于类的迭代器,它能作的每一件事生成器也能作到。因为自动创建了 __iter__() 和 __next__() 方法,生成器显得如此简洁。

另一个关键的功能在于两次执行之间,局部变量和执行状态都自动的保存下来。这使函数很容易写,而且比使用 self.index 和 self.data 之类的方式更清晰。

除了创建和保存程序状态的自动方法,当发生器终结时,还会自动抛出 StopIteration 异常。综上所述,这些功能使得编写一个正规函数成为创建迭代器的最简单方法。

生成器表达式

有时简单的生成器可以用简洁的方式调用,就像不带中括号的链表推导式。这些表达式是为函数调用生成器而设计的。生成器表达式比完整的生成器定义更简洁,但是没有那么多变,而且通常比等价的链表推导式更容易记。

例如:

>>> sum(i*i for i in range(10))                 # sum of squares285>>> xvec = [10, 20, 30]>>> yvec = [7, 5, 3]>>> sum(x*y for x,y in zip(xvec, yvec))         # dot product260>>> from math import pi, sin>>> sine_table = {x: sin(x*pi/180) for x in range(0, 91)}>>> unique_words = set(word  for line in page  for word in line.split())>>> valedictorian = max((student.gpa, student.name) for student in graduates)>>> data = 'golf'>>> list(data[i] for i in range(len(data)-1, -1, -1))['f', 'l', 'o', 'g']