Python __index__ 和评估顺序

标签 python

我期望下面的两个代码返回相同的结果,因为 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。因此求值的顺序类似于:

  1. 数据[i:i(3)]
  2. i(3) 计算为 3
  3. 构建切片 slice(i,3)
  4. 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/

相关文章:

python - “标签”对象没有属性 'count'

Python 正则表达式 : exclude\r\n

python - 在 Cython 中调用点积和线性代数运算?

python - scikit-learn 中具有相同属性的跨多列的标签编码

python - 为什么即使子进程已完成,Popen.poll() 也会返回 None 的返回码?

python - c中的按位旋转函数

python - 从文本文件复制并将编号的行写入另一个文件

python - 有没有办法使用 Pandas Python 将 excel 中具有相同键值的行中的所有值相加?

python - Plotly:如何调整 slider 和更新菜单的位置以为 x 轴刻度线腾出空间?

javascript - 像在 JS 中一样处理 Python 异常