"range(0,2)"和"list(range(0,2))"之间有什么区别?

26
需要了解在 Python 2.7 中 range(0,2)list(range(0,2)) 之间的区别。它们都返回一个列表,那么它们的具体区别是什么?请注意保留原有的 HTML 标签。
6个回答

49

在Python 3.x中,

range(0,3)返回一个不可变的可迭代对象类,让您可以对其进行迭代,它不会生成列表,并且不会将范围中的所有元素存储在内存中,而是在迭代过程中即时生成元素,而list(range(0,3))则生成一个列表(通过迭代所有元素并在内部附加到列表)。

示例-

>>> range(0,3)
range(0, 3)
>>> list(range(0,3))
[0, 1, 2]

理想情况下,如果您只想迭代该范围内的值,则range(0,3)(list(range(0,3)))更快,因为后者在开始迭代之前需要生成一个列表。

在Python 2.x中,range(0,3)会生成一个列表,而我们还有一个xrange()函数,与Python 3.x中的range()函数类似(xrange在Python 3.x中被重命名为range)。

对于Python 3.5,来自文档 -

范围对象实现了collections.abc.Sequence ABC,并提供特性,如包含测试、元素索引查找、切片和支持负索引

因此,您可以执行以下操作 -

>>> range(0,10)[5]
5
>>> range(0,10)[3:7]
range(3, 7)
>>> 5 in range(6,10)
False
>>> 7 in range(1,8)
True

而且所有这些都是常量时间操作,从这个测试中可以看出-

In [11]: %timeit a = xrange(0,1000000)[1000]
1000000 loops, best of 3: 342 ns per loop

In [12]: %timeit a = xrange(0,1000000)[10000]
1000000 loops, best of 3: 342 ns per loop

In [13]: %timeit a = xrange(0,1000000)[100000]
1000000 loops, best of 3: 342 ns per loop

In [14]: %timeit a = xrange(0,1000000)[999999]
1000000 loops, best of 3: 342 ns per loop

In [15]: %timeit a = xrange(0,10000000)[9999999]
1000000 loops, best of 3: 339 ns per loop

In [16]: %timeit a = xrange(0,1000000000000)[9999999999]
1000000 loops, best of 3: 341 ns per loop

那么在Python 3中,range(x,y)类似于生成器吗?自从我第一次看到这种行为以来,我一直在想... - Kyrubas
目前是有意的,因为我用于获取timeit示例的在线解释器是Python 2.7,所以我使用了xrange而不是range。但这应该没有关系,因为Python 3的range就是Python 2.x的xrange()。 - Anand S Kumar
好的,我明白了,就是这样的。只是想确认一下这是有意为之的。 - Scott

13

这取决于您使用的Python版本。

在Python 2.x中,range()返回一个列表,因此它们是等价的。

在Python 3.x中,range()返回一个不可变序列类型,您需要使用list(range(0,2))来获取一个列表。


5
实际上,range 函数不会返回生成器,而是一个不可变对象。尝试执行 next(range(0,5)) 语句,你就能理解了。 - Anand S Kumar
@AnandSKumar 现已更正。 - Yu Hao

3

基本上,两者的区别在于range(0, 2)是一个生成器函数,而list(range(0, 2))是一个实际的列表。

生成器函数用于循环。例如,文件的生成器函数将逐行读取非常大的文件。

def gen():
    for line in open("hugefile.csv", "r"):
        yield line #Gives back the line every time it is read, but forgets that line after

for line in gen():
    print(line)

这将逐行打印每一行,不会因为在这两个函数中只读取一个而导致计算机内存过载。然而,如果我们执行以下操作:
def readEntireFile():
    return [line for line in open("hugefile.csv", "r")] #Python has lazy ways of making lists, this is the same as returning a list with all the lines in the file

for line in readEntireFile():
    print(line)

第二部分看起来一样,但实际上并不相同。最初,我们循环遍历文件中的每一行,并在完成后继续下一行。在这里,Python 有一个包含所有行的列表:/,想象一下用 10GB 的文件做这件事情!你的代码会崩溃。
现在,让我们回到 range() 和 list(range())。
使用 for x in range(0, 6): 使我们进入范围内的下一个数字,并完全忘记之前的(打破语法)。
然而,使用 for x in list(range(0, 6)): 会将整个数字列表存储在内存中,与以下操作相同:
numlist = [x for x in range(6)]
for x in numlist:
    print(x)

当你需要代码中的整个数据列表时,请使用列表方法。但是,当你每次只需要一条数据(最简单的例子,按块复制文件)时,请使用生成器函数来节省空间。假设你不拥有极长的行,你可以仅使用54 MB 来复制文件的每100万行。然而,如果我们有一个微小的2KB文件,我们可以在不使用生成器的情况下直接复制它。在这种情况下,使用生成器不值得时间成本且速度较慢。

3

1

Range 生成一个 'range' 类的对象

它是否持久存在取决于它是否被赋值

a = range(10)
print(type(a))
print(a[0])
print(type(a[0]))

输出:

<class 'range'>
0
<class 'int'>

输出实际上是一个不可变的有序整数容器。从语义上讲,它是一个整数元组,但为了提高效率,Python将其实现为一个单独的“生成器”类,而不是元组类。这是一个很好的例子,说明在缺少编译的情况下,Python无法隐藏实现细节,程序员必须意识到这一点。

1

在Python3.x中,range有自己的类型

>>> range(1)
range(0, 1)
>>> type(range(1))
<class 'range'>

如果你想在for循环中使用range(),没问题。但是你不能纯粹地将它用作列表对象。你需要将其转换为列表才能这样做。

Python2示例:

>>> L = range(10)
>>> L[::-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

Python3 示例:

>>> L = range(10)
>>> L[::-1]
range(9, -1, -1)

1
你可以对一个范围进行切片 - >>> range(0,3)[1:3] range(1, 3) - Anand S Kumar
正如@AnandSKumar在他的答案中指出的那样,python3的range()是一个序列类型,并且具有与列表和元组相同的操作(除了连接和重复)https://docs.python.org/3/library/stdtypes.html#sequence-types-list-tuple-range - Scott
@Anand,你说的切片是正确的。我已经更新了我的回答,谢谢! - Chandan Nayak

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