为什么我们在通过 super 调用时必须使用 __dunder__ 方法而不是运算符?

问题描述:

为什么我们必须使用 __getitem__ 而不是通常的操作符访问?

Why do we have to use __getitem__ rather than the usual operator access?

class MyDict(dict):
    def __getitem__(self, key):
        return super()[key]

我们得到 TypeError: 'super' object is not subscriptable.

相反,我们必须使用 super().__getitem__(key),但我从来没有完全理解为什么 - 究竟是什么阻止了 super 以允许操作员访问的方式实现?

Instead we must use super().__getitem__(key), but I never fully understood why - what exactly is it that prevented super being implemented in a way that would allow the operator access?

Subscriptable 只是一个例子,我对 __getattr____init__ 等有同样的问题.

Subscriptable was just an example, I have the same question for __getattr__, __init__, etc.

docs 试图解释原因,但我不明白.

The docs attempt to explain why, but I don't understand it.

CPython 的错误跟踪器的 issue 805304,超级实例不支持项目分配", 雷蒙德·赫廷格 (Raymond Hettinger) 对感知到的困难进行了详细解释.

CPython's bug tracker's issue 805304, "super instances don't support item assignment", has Raymond Hettinger give a detailed explanation of perceived difficulties.

这不能自动工作的原因是,由于 Python 的方法缓存,这些方法必须在类中定义,而代理方法是在运行时找到的.

The reason this doesn't work automatically is that such methods have to be defined on the class due to Python's caching of methods, whilst the proxied methods are found at runtime.

他提供了一个补丁来提供这个功能的一个子集:

He offers a patch that would give a subset of this functionality:

+   if (o->ob_type == &PySuper_Type) {
+       PyObject *result;
+       result = PyObject_CallMethod(o, "__setitem__", "(OO)", key, value);
+       if (result == NULL)
+           return -1;
+       Py_DECREF(result);
+       return 0;
+   }
+ 

所以很明显可能.

然而,他总结了

我一直在想,这个人可以单独留下来记录超级对象只对其施展魔法显式属性查找.

I've been thinking that this one could be left alone and just document that super objects only do their magic upon explicit attribute lookup.

否则,完全修复它涉及将 Python 用于每一个直接从slots表调用函数的地方,然后使用属性查找添加后续调用,如果插槽是空的.

Otherwise, fixing it completely involves combing Python for every place that directly calls functions from the slots table, and then adding a followup call using attribute lookup if the slot is empty.

说到像 repr(obj) 这样的函数,我想我们想要标识自己而不是转发的超级对象调用目标对象的 __repr__() 方法.

When it comes to functions like repr(obj), I think we want the super object to identify itself rather than forwarding the call to the target object's __repr__() method.

争论似乎是如果 __dunder__ 方法被代理,那么 __repr__ 被代理或者它们之间存在不一致.super() 因此,可能不想代理这些方法,以免它太接近程序员的恐怖谷.

The argument seems to be that if __dunder__ methods are proxied, then either __repr__ is proxied or there is an inconsistency between them. super(), thus, might not want to proxy such methods lest it gets too near the programmer's equivalent of an uncanny valley.