Python学习之路(14)——迭代器

在Python中,有以下对象可以通过for语句来直接遍历:

一类是集合数据类型,如list、tuple、dict、set和str等;

一类是generator,包括生成器和带yield的generator function。

这些对象都可以被称为可迭代对象(Iterable)。

 

迭代器

迭代器对象要求支持迭代器协议的对象,在Python中,支持迭代器协议就是实现对象的iter()和next()方法。

这两个方法是迭代器最基本的方法,前者用来获得迭代器对象,后者用来获取容器中的下一个元素,并在结尾时引发StopIteration异常。

因此,我们将可以被next()函数调用并不断返回下一个值的对象成为迭代器:Iterator。

示例:

>>> str1 = 'I love you'
>>> it = iter(str1)
>>> it
<str_iterator object at 0x0000000003563080>
>>> next(it)
'I'
>>> next(it)
' '
>>> next(it)
'l'
>>> 

  

list、dict、str等数据类型是否是迭代器呢?

>>> from collections import Iterator
>>> isinstance([1, 2, 3], Iterator)
False
>>> isinstance({1: 'one'}, Iterator)
False
>>> isinstance('hello', Iterator)
False
>>> 
>>> isinstance(iter([1, 2, 3]), Iterator)
True
>>> 

  

可以看出list、dict等数据类型不是迭代器,而iter()函数可以把一个对象转换成迭代器Iterator。

因为Python的Iterator对象标识的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,指导没有数据时抛出StopIteration异常。可以把这个数据流看做一个有序序列,但我们却不能提前知道序列的长度,只能通过不断next()函数实现按需计算下一个数据,所有Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。

Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。

 

小结:

凡是可作用于for循环的对象都是Iterable类型;

凡是可作用于next()函数的对象都是Iterator类型。

 

实际上Python的for循环就是不断调用next()函数实现的,如:

>>> for x in list(range(5)):
	pass

>>> 

  

实际上完全等价于:

>>> it = iter(list(range(5)))
>>> while True:
	try:
		x = next(it)
	except StopIteration:
		break

	
>>>

  

迭代器的魔法方法__iter__()和__next__()

__iter__():该方法返回的是迭代器本身,实际上就是return self

__next__():该方法控制迭代器的迭代规则

下面以斐波那契数列为例:

>>> class Fibs:
	def __init__(self, n = 100):
		self.a = 0
		self.b = 1
		self.n = n
	def __iter__(self):
		return self
	def __next__(self):
		self.a, self.b = self.b, self.a + self.b
		if self.a > self.n:
			raise StopIterator
		return self.a

	
>>> fibs = Fibs()
>>> for each in fibs:
	print(each, end = ' ')

	
1 1 2 3 5 8 13 21 34 55 89 Traceback (most recent call last):
  File "<pyshell#72>", line 1, in <module>
    for each in fibs:
  File "<pyshell#68>", line 11, in __next__
    raise StopIterator
NameError: name 'StopIterator' is not defined
>>> fibs = Fibs(500)
>>> for each in fibs:
	print(each, end = ' ')

	
1 1 2 3 5 8 13 21 34 55 89 144 233 377 Traceback (most recent call last):
  File "<pyshell#76>", line 1, in <module>
    for each in fibs:
  File "<pyshell#68>", line 11, in __next__
    raise StopIterator
NameError: name 'StopIterator' is not defined
>>> 

  

posted on 2018-03-01 17:11  nicolas_Z  阅读(146)  评论(0)    收藏  举报

导航