索引范围对象时是否使用迭代协议?
Is the iteration protocol used when indexing a range object?
由于范围对象按需生成值,这是否意味着只要范围被索引,迭代协议就会被调用到该索引?
我的意思是什么时候:
>>> R = range(1,11)
>>> print(R[5])
6
既然R[5]
没有存储在内存中,是不是每次都通过创建一个新的迭代器来计算?如果不是,如何索引范围对象?
没有。不是。
但是range
同时支持迭代协议和索引(通过getitem)
这里没有创建迭代器,也没有迭代发生。 range
对象的实现使得 Python 在恒定时间内按需计算 R[5]
的值。1
如果索引 i
不是负数,则计算归结为:
i * step + start
因此,对于您的代码 R[5]
,这将是 5*1 + 1
,即 6。
如果索引i
为负数,则先将R
的长度加到i
上,然后再计算值:
(i + len(R)) * step + start
Python-内部
当您编写 R[5]
时,此 Python 语法最终会转换为对 PyObject_GetItem
的调用,它会检查对象 R
以了解它应该如何继续在索引 5 找到项目。
PyObject_GetItem
首先检查这个结构的tp_as_mapping
slot of the range
type. This is not null; it holds a reference to a struct called range_as_mapping
. PyObject_GetItem
then checks to see what is in the mp_subscript
field:
static PyMappingMethods range_as_mapping = {
(lenfunc)range_length, /* mp_length */
(binaryfunc)range_subscript, /* mp_subscript */
(objobjargproc)0, /* mp_ass_subscript */
};
正如您在上面的代码片段中看到的,它发现 range_subscript
函数占据了 mp_subscript
字段。2
现在 range_subscript
检查传递给它的参数(R
和 5
)来决定请求的是单个索引还是切片。整数 5
意味着只需要一个索引,因此该函数将值的计算委托给 compute_range_item
。如本答案第一部分所述,此函数执行 return 整数 6 的计算。
1 我假设您使用的是 CPython:其他 Python 实现可能会以不同方式实现 range
对象。
2 如果你要调用 len(R)
,你可以看到 mp_length
中的内部函数被调用来计算 [=19 的长度=](参见)。
由于范围对象按需生成值,这是否意味着只要范围被索引,迭代协议就会被调用到该索引?
我的意思是什么时候:
>>> R = range(1,11)
>>> print(R[5])
6
既然R[5]
没有存储在内存中,是不是每次都通过创建一个新的迭代器来计算?如果不是,如何索引范围对象?
没有。不是。
但是range
同时支持迭代协议和索引(通过getitem)
这里没有创建迭代器,也没有迭代发生。 range
对象的实现使得 Python 在恒定时间内按需计算 R[5]
的值。1
如果索引 i
不是负数,则计算归结为:
i * step + start
因此,对于您的代码 R[5]
,这将是 5*1 + 1
,即 6。
如果索引i
为负数,则先将R
的长度加到i
上,然后再计算值:
(i + len(R)) * step + start
Python-内部
当您编写 R[5]
时,此 Python 语法最终会转换为对 PyObject_GetItem
的调用,它会检查对象 R
以了解它应该如何继续在索引 5 找到项目。
PyObject_GetItem
首先检查这个结构的tp_as_mapping
slot of the range
type. This is not null; it holds a reference to a struct called range_as_mapping
. PyObject_GetItem
then checks to see what is in the mp_subscript
field:
static PyMappingMethods range_as_mapping = {
(lenfunc)range_length, /* mp_length */
(binaryfunc)range_subscript, /* mp_subscript */
(objobjargproc)0, /* mp_ass_subscript */
};
正如您在上面的代码片段中看到的,它发现 range_subscript
函数占据了 mp_subscript
字段。2
现在 range_subscript
检查传递给它的参数(R
和 5
)来决定请求的是单个索引还是切片。整数 5
意味着只需要一个索引,因此该函数将值的计算委托给 compute_range_item
。如本答案第一部分所述,此函数执行 return 整数 6 的计算。
1 我假设您使用的是 CPython:其他 Python 实现可能会以不同方式实现 range
对象。
2 如果你要调用 len(R)
,你可以看到 mp_length
中的内部函数被调用来计算 [=19 的长度=](参见