1.迭代器
在python中,有很多数据类型是属于可迭代对象。比如,元祖,列表,字典,字符串,文件等类型。
python标准的迭代器对象实现需要支持两个方法来实现迭代协议:
__iter__ returns the iterator object itself. This is used in for and in statements.
__next__ method returns the next value from the iterator.
If there is no more items to return then it should raise StopIteration exception.
内建函数iter()接收一个可迭代对象,返回一个迭代器。迭代器以类的方式实现,比如下面是内建的函数xrange:
class yrange:
def __init__(self, n):
self.i = 0
self.n = n
def __iter__(self):
return self
def next(self):
if self.i < self.n:
i = self.i
self.i += 1
return i
else:
raise StopIteration()
__iter__
方法是实现一个可迭代对象的,在后台,iter函数就是调用给定对象上的_iter__
函数。__iter__
的返回值是一个迭代器,它要有一个next方法,并在没有下一个元素的时候报StopIteration错误。注意:一个迭代器对象只能使用一次,这就意味着,当一个迭代器对象在调用next方法时,raise StopIteration的错误后,再调用next方法,还是会报同样的错误。
class zrange:
def __init__(self, n):
self.n = n
def __iter__(self):
return zrange_iter(self.n)
class zrange_iter:
def __init__(self, n):
self.i = 0
self.n = n
def __iter__(self):
# Iterators are iterables too.
# Adding this functions to make them so.
return self
def next(self):
if self.i < self.n:
i = self.i
self.i += 1
return i
else:
raise StopIteration()
注意: 迭代器和可迭代对象有什么区别和联系呢?
-
可迭代的对象有个 iter 方法,每次都实例化一个新的迭代器;而迭代器要实现 next 方法,返回单个元素,此外还要实现 iter 方法,返回迭代器本身。
因此,迭代器是可迭代的,但是,可迭代对象不是迭代器。 - 可迭代对象一定不能是自身的迭代器,也就是说,可迭代对象必须实现
__iter__
方法,但是不能实现__next__
方法。另一方面,迭代器应该一直可以迭代,迭代器的__iter__
方法应该返回自身。
2.生成器
只要在函数的定义体中有yield关键字,该函数就是生成器函数。调用生成器函数时,会返回一个生成器对象,也就是说,生成器函数时生成器工厂。
def yrange(n):
i = 0
while i < n:
yield i
i += 1
每次yield语句执行,都会产生一个新的值.所以,一个生成器也是一个迭代器,不用担心迭代协议。
当一个生成器函数被调用时,它返回一个生成器对象,当next方法被第一次调用时,函数开始执行直到yield语句,yield的值会在next方法调用时返回。
>>> def foo():
... print "begin"
... for i in range(3):
... print "before yield", i
... yield i
... print "after yield", i
... print "end"
...
>>> f = foo()
>>> f.next()
begin
before yield 0
0
>>> f.next()
after yield 0
before yield 1
1
>>> f.next()
after yield 1
before yield 2
2
>>> f.next()
after yield 2
end
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>>
例子:
def integers():
"""Infinite sequence of integers."""
i = 1
while True:
yield i
i = i + 1
def squares():
for i in integers():
yield i * i
def take(n, seq):
"""Returns first n values from the given sequence."""
seq = iter(seq)
result = []
try:
for i in range(n):
result.append(seq.next())
except StopIteration:
pass
return result
print take(5, squares()) # prints [1, 4, 9, 16, 25]
类形式的生成器(该类型的生成器是可重用的):
>>> class Counter(object):
... def __init__(self, low, high):
... self.low = low
... self.high = high
... def __iter__(self):
... counter = self.low
... while self.high >= counter:
... yield counter
... counter += 1
...
>>> gobj = Counter(5, 10)
>>> for num in gobj:
... print(num, end=' ')
...
5 6 7 8 9 10
>>> for num in gobj:
... print(num, end=' ')
...
5 6 7 8 9 10
但是,像下面这样的例子,一个生成器对象是不能重复使用的。
def counter_generator(low, high):
while low <= high:
yield low
low += 1
if __name__ == '__main__':
cg = counter_generator(5, 10)
for i in cg:
print i
for i in cg:
print i
# 第一个for循环可以打印出结果,但是第二个不能