简体   繁体   English

Python __index__ 和评估顺序

[英]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 之后。所以评估的顺序是这样的:

  1. data[i:i(3)]
  2. Evaluate i(3) to 3评估i(3)到 3
  3. Build the slice slice(i,3)构建切片slice(i,3)
  4. Inside 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM