转载

Python3.4 Tutorial : Python3.4 Tutorial9 - Classes (Part 4)

9.9 迭代器(Iterators)

你可能已经意识到了,大多数的容器对象都是可以使用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语句幕后就是对容器对象调用的itor()。这个函数返回一个迭代器对象,它定义了方法_ 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) ... m a p s 

9.10 生成器(Generators)

生成器是创建迭代器简单而有效的工具。它的写法和普通的函数类似,但是在返回数据的时候使用yield语句。next()每次调用到它的时候,生成器就会从它中断的地方恢复执行(resume)(它会记录下所有数据的值和最后执行的一条语句)。用一个例子来展示创建生成器是多么简单:

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

任何可以用生成器做到的事,都可用用上一节提到的基于类的迭代器完成。生成器会如此简洁是因为_ iter_ ()和_ next_ ()方法是自动创建的。

另一个关键特性是局部变量和执行状态是两次调用间被自动保存的。这使得函数更容易编写,并且比使用 self.indexself.data 这样的实例变量要简洁的多。

在生成器中断的时候除了能够自动创建方法、保存程序状态之外,也会自动引发StopIteration异常。总结一下,这些特性使得创建一个和普通函数没有区别的迭代器变得容易。

9.10 生成器表达式(Generator Expressions)

一些简单的生成器可以编写的像表达式一样简洁,只需要使用一种类似于列表生成式(list comprehensions)的语法,但是要把中括号[]替换成小括号()。这些表达式是为封闭函数需要立即使用生成器的情况而设计的。生成器表达式更简洁但是和完整的生成器定义相比功能较弱,它往往比等价的列表生成式更节约内存。

例子:

>>> sum(i*i for i in range(10))                 # sum of squares 285  >>> xvec = [10, 20, 30] >>> yvec = [7, 5, 3] >>> sum(x*y for x,y in zip(xvec, yvec))         # dot product 260  >>> 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'] 
正文到此结束
Loading...