range() 真的创建列表吗?

46 投票
4 回答
19408 浏览
提问于 2025-04-18 03:45

我的教授和这个人都说range会生成一个数值列表。

“注意:range函数只是返回一个包含从x到y-1的数字的列表。例如,range(5, 10)返回的列表是[5, 6, 7, 8, 9]。”

我觉得这个说法不太准确,因为:

type(range(5, 10))
<class 'range'>

而且,使用range生成的整数,唯一明显的访问方式就是一个一个地遍历,这让我觉得把range称作列表是不对的。

4 个回答

0

Python3

使用 range 函数的 for 循环

要理解在 Python3 中 for i in range() 的意思,我们首先需要了解 range() 函数是怎么工作的。

range() 函数用生成器来产生数字。它并不是一次性生成所有数字。

正如你所知道的,range() 返回的是一个 range 对象。这个 range 对象无论表示的范围有多大,都只占用相同(很小的)内存。它只存储起始值、结束值和步长,然后根据需要计算每个数字和子范围。

也就是说,只有当 for 循环需要下一个值时,它才会生成下一个值。在每次循环中,它会生成下一个值,并把它赋值给迭代变量 i

所以这意味着 range() 会随着循环的进行一个一个地生成数字。 这样可以节省很多内存,使得 range() 更快、更高效。

参考: PyNative - 使用 range() 的 for 循环

2

在Python 2.x版本中,使用range会创建一个列表。如果你只需要用到一次range,那就没问题;但如果要用多次的话,建议使用xrange,因为它会生成一个生成器,这样可以减少内存的使用,有时候也能节省时间,因为它是懒加载的方式。

在Python 3.x版本中没有xrange,range的功能就相当于Python 2.x中的xrange。

想了解更多,可以参考这个问题: Python 2.X中range和xrange函数有什么区别?

8

这要看情况。

在 Python 2.x 版本中,range 会生成一个列表(列表也是一种序列),而 xrange 则会生成一个 xrange 对象,这个对象可以用来逐个遍历值。

而在 Python 3.x 版本中,range 生成的是一个可迭代的对象(更具体来说,是一种序列)。

104

在Python 2.x中,range会返回一个列表,但在Python 3.x中,range返回的是一种不可变的序列,类型是range

Python 2.x:

>>> type(range(10))
<type 'list'>
>>> type(xrange(10))
<type 'xrange'>

Python 3.x:

>>> type(range(10))
<class 'range'>

在Python 2.x中,如果你想得到一个可迭代的对象,像在Python 3.x中那样,你可以使用xrange函数,它返回的是一种不可变的序列,类型是xrange

xrange相比于range在Python 2.x中的优点:

xrange()range()的优势不大(因为xrange()在请求值时仍然需要创建这些值),除非在内存紧张的机器上使用非常大的范围,或者当范围内的所有元素都不会被使用时(比如循环通常用break结束)。

注意:

此外,访问range()创建的整数的唯一明显方法是通过迭代它们。

其实并不是这样。因为Python 3中的range对象是不可变的序列,它们也支持索引。引用range函数的文档:

范围实现了所有常见的序列操作,除了连接和重复。

...

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

例如,

>>> range(10, 20)[5]
15
>>> range(10, 20)[2:5]
range(12, 15)
>>> list(range(10, 20)[2:5])
[12, 13, 14]
>>> list(range(10, 20, 2))
[10, 12, 14, 16, 18]
>>> 18 in range(10, 20)
True
>>> 100 in range(10, 20)
False

所有这些操作都可以在这个不可变的range序列上进行。


最近,我遇到了一个问题,我觉得在这里提到它是合适的。考虑这段Python 3.x代码:

from itertools import islice
numbers = range(100)
items = list(islice(numbers, 10))
while items:
    items = list(islice(numbers, 10))
    print(items)

人们会期望这段代码打印出每十个数字,直到99。但它会无限运行。你能想出原因吗?

解决方案

因为range返回的是一个不可变的序列,而不是一个迭代器对象。所以,每当对range对象使用islice时,它总是从头开始。可以把它想象成一个不可变列表的替代品。现在问题来了,如何解决这个问题?很简单,你只需要从中获取一个迭代器。只需将

numbers = range(100)

改为

numbers = iter(range(100))

现在,numbers是一个迭代器对象,它会记住之前迭代了多长时间。所以,当islice迭代它时,它会从上次结束的地方开始。

撰写回答