【问题标题】:X.__getitem__(1) vs type(X).__getitem__(X, 1)X.__getitem__(1) 与类型(X).__getitem__(X, 1)
【发布时间】:2021-06-28 05:36:07
【问题描述】:
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)在C类中找不到__getitem__方法,不应该调用__getattr__(self, name)函数吗?

X.__getitem__(1) 在实例和类中找不到__getitem__,因此它调用__getattr__(self, name)

为什么一个有效而一个无效?我读到特殊方法查找会跳过__getattr__ 函数(如果隐式调用?),如X[1],但是,在这种情况下我明确调用它。

【问题讨论】:

    标签: python operator-overloading


    【解决方案1】:

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

    根据那里的示例(复制如下)使用__len__ 方法,您的代码中的type(X).__getitem__ 将调用元类中的__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!
    

    C 类中的__getattribute__ 被调用以查找__getitem__,它返回绑定到字符串"spam"__getitem__。当使用参数 1 调用时,返回位置 1 处的字母 p

    但是:

    type(X).__getitem__(X, 1)
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-09-21
      • 2011-09-24
      • 2012-10-15
      • 2011-08-17
      • 1970-01-01
      • 2019-12-04
      • 1970-01-01
      • 2011-11-20
      相关资源
      最近更新 更多