专栏名称: Python开发者
人生苦短,我用 Python。伯乐在线旗下账号「Python开发者」分享 Python 相关的技术文章、工具资源、精选课程、热点资讯等。
目录
相关文章推荐
Python爱好者社区  ·  DeepSeek下棋靠忽悠赢了ChatGPT ... ·  2 天前  
Python爱好者社区  ·  DeepSeek杀疯了! ·  16 小时前  
Python爱好者社区  ·  太强了!35个python案例.pdf ·  昨天  
Python中文社区  ·  用 DeepSeek 快速打造自己的 AI ... ·  昨天  
Python开发者  ·  7118 ... ·  3 天前  
51好读  ›  专栏  ›  Python开发者

完全理解 Python 迭代对象、迭代器、生成器

Python开发者  · 公众号  · Python  · 2017-06-25 20:01

正文

点击 上方蓝字 ,快速关注我们)


编译:伯乐在线/刘志军 ,微信公号:Python之禅(ID:VTtalk)

foofish.net/iterators-vs-generators.html

如有好文章投稿,请点击 → 这里了解详情


本文源自RQ作者的一篇博文,原文是Iterables vs. Iterators vs. Generators,俺写的这篇文章是按照自己的理解做的参考翻译,算不上是原文的中译版本,推荐阅读原文,谢谢网友指正。


在了解Python的数据结构时,容器(container)、可迭代对象(iterable)、迭代器(iterator)、生成器(generator)、列表/集合/字典推导式(list,set,dict comprehension)众多概念参杂在一起,难免让初学者一头雾水,我将用一篇文章试图将这些概念以及它们之间的关系捋清楚。


容器(container)


容器是一种把多个元素组织在一起的数据结构,容器中的元素可以逐个地迭代获取,可以用in, not in关键字判断元素是否包含在容器中。通常这类数据结构把所有的元素存储在内存中(也有一些特例,并不是所有的元素都放在内存,比如迭代器和生成器对象)在Python中,常见的容器对象有:


  • list, deque, ….

  • set, frozensets, ….

  • dict, defaultdict, OrderedDict, Counter, ….

  • tuple, namedtuple, …

  • str


容器比较容易理解,因为你就可以把它看作是一个盒子、一栋房子、一个柜子,里面可以塞任何东西。从技术角度来说,当它可以用来询问某个元素是否包含在其中时,那么这个对象就可以认为是一个容器,比如 list,set,tuples都是容器对象:


>>> assert 1 in [ 1 , 2 , 3 ] # lists

>>> assert 4 not in [ 1 , 2 , 3 ]

>>> assert 1 in { 1 , 2 , 3 } # sets

>>> assert 4 not in { 1 , 2 , 3 }

>>> assert 1 in ( 1 , 2 , 3 ) # tuples

>>> assert 4 not in ( 1 , 2 , 3 )


询问某元素是否在dict中用dict的中key:


>>> d = { 1 : 'foo' , 2 : 'bar' , 3 : 'qux' }

>>> assert 1 in d

>>> assert 'foo' not in d # 'foo' 不是dict中的元素


询问某substring是否在string中:


>>> s = 'foobar'

>>> assert 'b' in s

>>> assert 'x' not in s

>>> assert 'foo' in s


尽管绝大多数容器都提供了某种方式来获取其中的每一个元素,但这并不是容器本身提供的能力,而是可迭代对象赋予了容器这种能力,当然并不是所有的容器都是可迭代的,比如:Bloom filter,虽然Bloom filter可以用来检测某个元素是否包含在容器中,但是并不能从容器中获取其中的每一个值,因为Bloom filter压根就没把元素存储在容器中,而是通过一个散列函数映射成一个值保存在数组中。


可迭代对象(iterable)


刚才说过,很多容器都是可迭代对象,此外还有更多的对象同样也是可迭代对象,比如处于打开状态的files,sockets等等。但凡是可以返回一个迭代器的对象都可称之为可迭代对象,听起来可能有点困惑,没关系,先看一个例子:


>>> x = [ 1 , 2 , 3 ]

>>> y = iter ( x )

>>> z = iter ( x )

>>> next ( y )

1

>>> next ( y )

2

>>> next ( z )

1

>>> type ( x )

< class 'list' >

>>> type ( y )

< class 'list_iterator' >


这里x是一个可迭代对象,可迭代对象和容器一样是一种通俗的叫法,并不是指某种具体的数据类型,list是可迭代对象,dict是可迭代对象,set也是可迭代对象。y和z是两个独立的迭代器,迭代器内部持有一个状态,该状态用于记录当前迭代所在的位置,以方便下次迭代的时候获取正确的元素。迭代器有一种具体的迭代器类型,比如list_iterator,set_iterator。可迭代对象实现了__iter__方法,该方法返回一个迭代器对象。


当运行代码:


x = [ 1 , 2 , 3 ]

for elem in x :

...


实际执行情况是:


反编译该段代码,你可以看到解释器显示地调用GET_ITER指令,相当于调用iter(x),FOR_ITER指令就是调用next()方法,不断地获取迭代器中的下一个元素,但是你没法直接从指令中看出来,因为他被解释器优化过了。


>>> import dis

>>> x = [ 1 , 2 , 3 ]

>>> dis . dis ( 'for _ in x: pass' )

1 0 SETUP _ LOOP 14 ( to 17 )

3 LOAD _ NAME 0 ( x )

6 GET_ITER

>> 7 FOR _ ITER 6 ( to 16 )

10 STORE _ NAME 1 ( _ )

13 JUMP _ ABSOLUTE 7

>> 16 POP_BLOCK

>> 17 LOAD _ CONST 0 ( None )

20 RETURN_VALUE


迭代器(iterator)


那么什么迭代器呢?它是一个带状态的对象,他能在你调用next()方法的时候返回容器中的下一个值,任何实现了__iter__和__next__()(python2中实现next())方法的对象都是迭代器,__iter__返回迭代器自身,__next__返回容器中的下一个值,如果容器中没有更多元素了,则抛出StopIteration异常,至于它们到底是如何实现的这并不重要。


所以,迭代器就是实现了工厂模式的对象,它在你每次你询问要下一个值的时候给你返回。有很多关于迭代器的例子,比如itertools函数返回的都是迭代器对象。


生成无限序列:


>>> from itertools import count

>>> counter = count ( start = 13 )

>>> next ( counter )

13

>>> next ( counter )

14


从一个有限序列中生成无限序列:


>>> from itertools import cycle

>>> colors = cycle ([ 'red' , 'white' , 'blue' ])

>>> next ( colors )

'red'

>>> next ( colors )

'white'

>>> next ( colors )

'blue'

>>> next ( colors )

'red'


从无限的序列中生成有限序列:


>>> from itertools import islice

>>> colors = cycle ([ 'red' , 'white' , 'blue' ]) # infinite

>>> limited = islice ( colors , 0 , 4 ) # finite

>>> for x in limited :

... print ( x )

red

white

blue

red


为了更直观地感受迭代器内部的执行过程,我们自定义一个迭代器,以斐波那契数列为例:


class Fib :

def __init__ ( self ) :

self . prev = 0

self . curr = 1

def __iter__ ( self ) :

return self

def __next__ ( self ) :

value = self . curr

self . curr += self . prev

self . prev = value

return value

>>> f = Fib ()

>>> list ( islice ( f , 0 , 10 ))

[ 1 , 1 , 2 ,







请到「今天看啥」查看全文