for的本质
容器对象都可以直接用于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循环停止。
正如iter()调用容器对象的__iter__()一样,next()调用对象的__next__()。
迭代器与可迭代对象
iter()的调用返回拥有方法__next__()的迭代器对象,用于迭代数据。而定义了__iter__(),可作为参数用于iter()的对象则是可迭代对象,上述例子中的各种容器对象都是可迭代对象。
构造符合上述迭代协议的对象,即可直接用于for语句
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
一个对象可以既是迭代器对象的同时又是可迭代对象。
生成器
生成器是一种简单,功能强大的创建迭代器的工具。生成器的定义和一般的函数一致,只不过在返回数据的地方不用return,而用yield语句。
每一次next()被调用,生成器都会恢复到之前的上下文继续执行。
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__()被自动的创建,以及StopIteration被自动抛出。同时由于生成器的每次恢复执行,都能自动恢复之前的上下文,所以不再需要上述中基于类的迭代器版本中的实例变量self.index,和self.data.
生成器表达式
类似列表推导式,简单的生成器可以用更简洁的生成器表达式的方式创建,只需把大括号改为小括号。生成器表达式常用在生成器直接被作为外围函数参数使用的情景。
>>> data = 'golf'
>>> list(data[i] for i in range(len(data)-1, -1, -1))
['f', 'l', 'o', 'g']
>>> sum(i*i for i in range(10)) # sum of squares
285
>>> unique_words = set(word for line in page for word in line.split())
>>> valedictorian = max((student.gpa, student.name) for student in graduates)
生成器表达式比等价的列表推导式对内存更加友好,但是生成器表达式无完整定义的生成器表达能力强。