我期望下面的两个代码返回相同的结果,因为 https://docs.python.org/3.7/reference/expressions.html#evaluation-order 。然而,在第二种情况下,Counter 类中的 __index__
看起来是在 __call__
之后调用的。是因为 __index__
仅在到达 ]
时才被调用吗?或者还有其他解释吗?
class Counter:
def __init__(self, start=0):
self._i = start
def __call__(self, step:int=None):
if step is not None:
self._i += step
return self._i
def __index__(self):
return self._i
data = list(range(0, 10))
i = Counter(0)
data[i():i(3)]
返回[0,1,2]
i = Counter(0)
data[i:i(3)]
返回[]
PS:Counter 类的目标是允许类似于 python < 3.8 中的赋值语法
i = 0
data[i: (i := i+3)]
最佳答案
data[i:i(3)]
相当于 data.__getitem__(slice(i, i(3)))
;在 data.__getitem__
体内实际需要切片的起始元素之前,i.__index__
不会被调用,但在 i(3) 之后
已经将 i._step
增加到 3。因此求值的顺序类似于:
数据[i:i(3)]
- 将
i(3)
计算为 3 - 构建切片
slice(i,3)
- 在
data.__getitem__
内部,需要i
的整数值,因此调用i.__index__
,返回3。<
您可以通过反汇编索引操作来看到这一点:
>>> import dis
>>> dis.dis('data[i:i(3)]')
1 0 LOAD_NAME 0 (data)
2 LOAD_NAME 1 (i)
4 LOAD_NAME 1 (i)
6 LOAD_CONST 0 (3)
8 CALL_FUNCTION 1
10 BUILD_SLICE 2
12 BINARY_SUBSCR
14 RETURN_VALUE
首先调用i(3)
(在偏移量8处),然后构建切片(在偏移量10处),最后调用data.__getitem__
(在偏移 12)。
关于Python __index__ 和评估顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59616123/