X.__getitem__(1) vs 类型(X).__getitem__(X, 1)

X.__getitem__(1) vs type(X).__getitem__(X, 1)

class C:
    data = 'spam'
    def __getattr__(self, name):
        print('getattr:', name)
        return getattr(self.data, name) 
X = C()
X.__getitem__(1) // <-- works!
type(X).__getitem__(X, 1) // <-- AttributeError: type object 'C' has no attribute '__getitem__'

既然type(X).__getitem__(X, 1)在class C中找不到__getitem__方法,难道不应该调用__getattr__(self, name)函数吗?

X.__getitem__(1) 在实例和 class 中找不到 __getitem__ 所以它调用 __getattr__(self, name).

为什么一个工作,一个不工作?我读到特殊方法查找会像 X[1] 一样跳过 __getattr__ 函数(如果隐式调用?),但是,在这种情况下我会显式调用它。

special method lookup docs 的最后一部分显示绕过 __getattribute__ 时的异常情况。

根据那里的示例(在下面复制)使用 __len__ 方法,您代码中的 type(X).__getitem__ 会调用元 class 中的 __getattribute__,但是您还没有定义它。

>>> class Meta(type):
...     def __getattribute__(*args):
...         print("Metaclass getattribute invoked")
...         return type.__getattribute__(*args)
...
>>> class C(object, metaclass=Meta):
...     def __len__(self):
...         return 10
...     def __getattribute__(*args):
...         print("Class getattribute invoked")
...         return object.__getattribute__(*args)
...
>>> c = C()
>>> c.__len__()                 # Explicit lookup via instance
Class getattribute invoked
10
>>> type(c).__len__(c)          # Explicit lookup via type
Metaclass getattribute invoked
10
>>> len(c)                      # Implicit lookup
10

使用此信息,可以解释观察到的行为:

X.__getitem__(1) # <-- works!

__getattribute__ 从 class C 被调用来查找 __getitem__,它 returns 将 __getitem__ 绑定到字符串 "spam".当使用参数 1 调用时,返回位置 1 的字母 p

但是:

type(X).__getitem__(X, 1)

__getattribute__ 来自 C 的 metaclass 将被调用,但它没有在那里定义。结果是 AttributeError.