[英]Python __index__ and evaluation order
I was expecting the two code below to return the same result because of https://docs.python.org/3.7/reference/expressions.html#evaluation-order .由于https://docs.python.org/3.7/reference/expressions.html#evaluation-order ,我期望下面的两个代码返回相同的结果。 However it looks like
__index__
from Counter class is called after __call__
in the second case.然而,在第二种情况下,在
__call__
之后__call__
了 Counter 类中的__index__
。 Is it because __index__
gets called only when reaching ]
?是因为
__index__
仅在到达]
__index__
被调用吗? Or is there another explanation ?或者还有其他解释吗?
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)]
returns [0, 1, 2]
返回
[0, 1, 2]
i = Counter(0)
data[i:i(3)]
returns []
返回
[]
PS: The goal of the Counter class is to allow assignment like syntax in python < 3.8 PS:Counter 类的目标是在 python < 3.8 中允许类似语法的赋值
i = 0
data[i: (i := i+3)]
data[i:i(3)]
is equivalent to data.__getitem__(slice(i, i(3)))
; data[i:i(3)]
等价于data.__getitem__(slice(i, i(3)))
; i.__index__
doesn't get called until the starting element of the slice is actually needed, inside the body of data.__getitem__
, but after i(3)
has already incremented i._step
to 3. So the order of evaluation is something like: i.__index__
在实际需要切片的起始元素之前不会被调用,在data.__getitem__
的主体内,但是在i(3)
已经将i._step
增加到 3 之后。所以评估的顺序是这样的:
data[i:i(3)]
i(3)
to 3i(3)
到 3slice(i,3)
slice(i,3)
data.__getitem__
, the integer value of i
is needed, so i.__index__
is called, which returns 3.data.__getitem__
,需要i
的整数值,因此调用i.__index__
,返回 3。 You can see this by disassembling the indexing operation:您可以通过反汇编索引操作来看到这一点:
>>> 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
First i(3)
is called (at offset 8), then the slice is built (at offset 10), and finally data.__getitem__
is called (at offset 12).首先调用
i(3)
(偏移量 8),然后构建切片(偏移量 10),最后调用data.__getitem__
(偏移量 12)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.