Python - 如何重写实例的__getattribute__?

4 投票
4 回答
1672 浏览
提问于 2025-04-15 15:02

这个问题对我来说有点棘手。之前我成功地用类似下面的代码覆盖了一个实例的方法:

def my_method(self, attr):
    pass

instancemethod = type(self.method_to_overwrite)
self.method_to_overwrite = instancemethod(my_method, self, self.__class__)

这个方法对我来说效果很好;但是现在我想覆盖一个实例的 __getattribute__() 函数,但这对我来说不太奏效,原因是这个方法似乎是

<type 'method-wrapper'>

有没有办法解决这个问题呢?我找不到关于 method-wrapper 的好文档。

4 个回答

4

你不能在实例级别覆盖特殊方法。对于新式类来说,特殊方法的隐式调用只有在这些方法定义在对象的类型上时才能保证正常工作,而不是在对象的实例字典中。

6

你想要在每个实例上单独修改属性查找的方式?虽然我不知道你为什么想这么做,但我猜可能有更简单的方法可以达到你的目的。如果你真的需要这样做,正如Aaron所说,你需要在类上安装一个重定向的__getattribute__处理器,因为Python只在类上查找特殊方法,而忽略实例上定义的内容。

另外,你还得特别小心,避免陷入无限递归的情况:

class FunkyAttributeLookup(object):
    def __getattribute__(self, key):
        try:
            # Lookup the per instance function via objects attribute lookup
            # to avoid infinite recursion.
            getter = object.__getattribute__(self, 'instance_getattribute')
            return getter(key)
        except AttributeError:
            return object.__getattribute__(self, key)

f = FunkyAttributeLookup()
f.instance_getattribute = lambda attr: attr.upper()
print(f.foo) # FOO

还有,如果你在实例上重写方法,其实你不需要自己去实例化方法对象。你可以使用描述符协议来生成方法,或者直接传递self参数。

 #descriptor protocol
 self.method_to_overwrite = my_method.__get__(self, type(self))
 # or curry
 from functools import partial
 self.method_to_overwrite = partial(my_method, self)
1

我认为 method-wrapper 是一个用C语言写的方法的包装器。

撰写回答