Python range() 和 zip() 对象类型

67

我知道类似 range()zip() 的函数可以在for循环中使用。但是我原以为 range() 会输出一个列表,就像unix shell中的seq一样。如果我运行以下代码:

a=range(10)
print(a)
输出结果是range(10),表明它不是一个列表而是另一种类型的对象。zip()的打印行为类似,输出类似以下内容:
<zip object at "hexadecimal number">
所以我的问题是它们是什么,将它们制作成这样有什么优势,并且我如何在不循环遍历它们的情况下将它们的输出转换为列表?

1
看起来像是 Python 3。使用 a = list(range(10)) - Matthias
2
除了这里的好答案之外,我建议阅读Python yield关键字解释的答案,以了解生成器——为什么您的函数可能还不想返回列表的绝佳示例。 - Lukas Graf
3个回答

104

您必须使用Python 3。

在Python 2中,ziprange 对象的行为确实与您所建议的一样,返回列表。它们被更改为生成器-like对象,可以按需产生元素,而不是将整个列表扩展到内存中。其中一个优点是在它们的典型用例(例如迭代)中具有更高的效率。

"延迟"版本也存在于Python 2.x中,但它们具有不同的名称,即xrangeitertools.izip

要一次性检索所有输出并将其放入熟悉的列表对象中,只需调用list以迭代和消耗内容:

>>> list(range(3))
[0, 1, 2]
>>> list(zip(range(3), 'abc'))
[(0, 'a'), (1, 'b'), (2, 'c')]

1
虽然这些对象是惰性的,但我认为将它们描述为类似于生成器是误导性的,例如请参见https://dev59.com/_Wcs5IYBdhLWcg3wJglV - Chris_Rands
1
@Chris_Rands 从最重要的意义上讲,它们就像生成器一样,在需要时产生元素。我认为我的描述是公正的;我小心翼翼地没有真正称它们为生成器,而且这些差异对于这个问题来说并不重要。 - wim
真的,也许我第一条评论的语气有些不公平,抱歉。但是我还是会保留它,因为链接提供了一些关于范围对象的进一步细节,对那些感兴趣的人来说很有帮助。 - Chris_Rands
zip是一个迭代器:
z = zip((1,2),(3,4)) next(z) (1, 3)
- Dmitriy Sintsov

28
在Python 3.x中,range返回一个范围对象,而不是像Python 2.x中一样返回一个列表。同样,zip现在返回一个zip对象,而不是一个列表。
要将这些对象作为列表获取,请将它们放入list中:
>>> range(10)
range(0, 10)
>>> list(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> zip('abc', 'abc')
<zip object at 0x01DB7120>
>>> list(zip('abc', 'abc'))
[('a', 'a'), ('b', 'b'), ('c', 'c')]
>>>

虽然一开始可能看起来不太有用,但 range 和 zip 行为的这种改变实际上提高了效率。这是因为 zip 和 range 对象会根据需要生成项目,而不是一次性创建列表来保存它们。这样做可以节省内存消耗并提高操作速度。

7

Range(在Python 2.*中为xrange)对象是不可变序列,而zip(分别为itertools.izip)是一个生成器对象。要从生成器或序列中创建列表,只需将其转换为列表即可。例如:

>>> x = range(10) 
>>> list(x)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

但是它们在元素生成方式上有所不同。普通生成器是可变的,如果迭代,它们会用尽其内容,而 range 是不可变的,不会用尽其内容。
>>> list(x) # x is a range-object
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] # second cast to list, contents is the same
>>> y = zip('abc', 'abc')
>>> list(y) # y is a generator
[('a', 'a'), ('b', 'b'), ('c', 'c')]
>>> list(y) 
[] # second cast to list, content is empty!

我在REPL中玩弄这些示例,遵循此前对这个问题的回答。当我第一次使用zip生成的非生成器时,我有点:facepalm:,直到我看到你提到第二次转换为列表会导致空内容。谢谢你! - wonderfulthunk
当我尝试在list()中打印zip对象时,出现了列表不可调用的错误。 - Toma

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