生成器 vs 序列对象

13
我知道rangexrange的区别。
但我很惊讶地发现,xrange不是generator,而是sequence object

那么它们有什么区别呢?如何创建一个sequence object,以及在什么情况下使用它比使用generator更好?
2个回答

15
由于支持sequence methods interfacexrange成为一个序列对象。例如,您可以索引它(这是使用原始生成器无法实现的):
print xrange(30)[5]  # No Error

换句话说,

  • 如果一个对象支持该链接中定义的所有方法,则称其为序列。
  • 如果它是一个生成器,那么它可能只支持一对方法.next.__next__ 是最重要的)1
  • 还有一个中间状态叫做“可迭代”——“可迭代”通常具有定义良好的__iter__方法,该方法返回“生成器”(具有明确定义的.next.__next__3方法的对象)
  • 为了完整起见,你经常会看到人们说“迭代器”,它们与生成器非常相似(实现__iter__,返回对象本身并具有明确定义的next和/或__next__方法)。

更正式的定义可以在文档词汇表中找到。

1生成器也支持__iter__并简单地返回自身。因此,从技术上讲,所有生成器也都是可迭代的(和迭代器!),但不是所有可迭代的(迭代器)都是生成器。
2__len__ + __getitem__足以创建一个可迭代对象,正如评论中指出的那样。
3__next__是Python3.x的方法名称。


@200OK -- 这在 Python2.x 中是正确的,但在 Python3.x 中已经“修复”了。__getitem__ + __len__ 也足以创建一个可迭代对象。 - mgilson
1
你还应该提到“迭代器”这个词,它是一个从__iter__()返回自身并且有(__)next(__)的对象。生成器只是其中的一个例子。iter([1, 2, 3])也具有相同的属性。请注意,一旦使用过,它们就会被耗尽并且无法再使用。 - glglgl
@glglgl -- 这是“迭代器”真正的定义吗?我总是将其与“可迭代对象”同步使用。 - mgilson
1
@mgilson 是的。请参见这里,特别是这里 - glglgl
1
一个重要的区别是:您可以在可迭代对象(例如列表)上多次操作,但只能在迭代器上操作一次(之后它将保持耗尽状态)。请参见 a = [1, 2, 3]; for i in a: print i; for i in a: print i; b = iter(a); for i in b: print i; for i in b: print i(将 ; 替换为换行符)。 - glglgl
显示剩余4条评论

2

sequence object 是一种特殊的C提供的类型。一个 generator 可以由用户代码编写。

这是Python 2的事情 - 在Python 3中:

>>> print(type(range(1)))
<class 'range'>
>>> print(type(xrange(1)))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'xrange' is not defined

Python2:

Python 2.7.5+ (default, Feb 27 2014, 19:37:08) 
[GCC 4.8.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> print type(xrange(1))
<type 'xrange'>

谢谢,但我已经知道Python 2和3之间的区别了,不过看到两个版本之间类型不同还是很好的。 - MoiTux
被踩了。最好根据提供的接口而不是实现细节来推理差异。 - MrR

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接