Python Iterator 学习小记
The reference link: Implicit sequences by cs61a
Iterator
Python提供了一种统一的方式来顺序处理容器值(container value)的元素(elements),称为迭代器(Iterator)。迭代器是一个对象(Object),它提供对值(values)的顺序访问。
primes = [2, 3, 5, 7]
type(primes)
<class 'list'>
iterator = iter(primes)
type(iterator)
<class 'list_iterator'>
next(iterator)
2
>>> next(iterator)
3
>>> next(iterator)
5
当Iterator处在最后一个元素时调用next(iterator)
,Python会引发StopIteration
异常(exception)。
>>> next(iterator)
7
>>> next(iterator)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>> try:
next(iterator)
except StopIteration:
print('No more values')
No more values
我们可以将Iterator赋值给另一个变量:
>>> r = range(3, 13)
>>> s = iter(r) # 1st iterator over r
>>> next(s)
3
>>> next(s)
4
>>> t = iter(r) # 2nd iterator over r
>>> next(t)
3
>>> next(t)
4
>>> u = t # Alternate name for the 2nd iterator
>>> next(u)
5
>>> next(u)
6
注意,赋值并非c++中的复制(copy),而是绑定(binding),即上例中的u
和t
指向同一个Iterator。
Iterables
任何可以产生Iterator的值都称为可迭代值(Iterable value)。在Python中,可迭代值是任何可以传递给内置iter函数的值。可迭代对象包括序列值,如list和tuple,以及其他容器,如set和dictionary。Iterator也iterable,因为它们可以传递给iter函数。
>>> d = {'one': 1, 'two': 2, 'three': 3}
>>> d
{'one': 1, 'three': 3, 'two': 2}
>>> k = iter(d)
>>> next(k)
'one'
>>> next(k)
'three'
>>> v = iter(d.values())
>>> next(v)
1
>>> next(v)
3
注意
dict是(在python3.6及之后版本)是有序的,其key、value和item都是iterable。
For statement
for的本质生成一个iterator并迭代。
>>> counts = [1, 2, 3]
>>> for item in counts:
print(item)
1
2
3
它可以写成这样:
>>> items = counts.__iter__()
>>> try:
while True:
item = items.__next__()
print(item)
except StopIteration:
pass
1
2
3
我们用except
处理StopIteration
异常但不做任何处理。
注意:iter
函数本质是调用Class里的内置__iter__
函数,next
同理,故iter(counts)
和counts.__iter__()
等价。
Generators and Yield Statements
生成器(Generator)是由一种称为生成器(generator function)函数的特殊函数类返回的Iterator。生成器函数与常规函数的区别在于,它们的函数体中不包含return语句,而是使用yield语句返回一个系列的元素。
>>> def letters_generator():
current = 'a'
while current <= 'd':
yield current
current = chr(ord(current)+1)
>>> for letter in letters_generator():
print(letter)
a
b
c
d
当触发yield语句时,它会暂停并返回yield后的值,但不会破坏新生成的环境。当__next__
再次被调用时,函数从原来位置上继续执行。
>>> letters = letters_generator()
>>> type(letters)
<class 'generator'>
>>> letters.__next__()
'a'
>>> letters.__next__()
'b'
>>> letters.__next__()
'c'
>>> letters.__next__()
'd'
>>> letters.__next__()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
于是我们可以自定义迭代接口(Iterator Interface):
>>> class Letters:
def __init__(self, start='a', end='e'):
self.start = start
self.end = end
def __iter__(self):
return LetterIter(self.start, self.end)
class LetterIter:
"""An iterator over letters of the alphabet in ASCII order."""
def __init__(self, start='a', end='e'):
self.next_letter = start
self.end = end
def __next__(self):
if self.next_letter == self.end:
raise StopIteration
letter = self.next_letter
self.next_letter = chr(ord(letter)+1)
return letter