如何在Python中为一个已实例化的类重写__repr__方法

8

我正在使用一个第三方库,其中一个类的repr效果不佳,我希望在该类的实例创建后覆盖它。

我已经了解到如何在现有对象中创建绑定方法。

class toy():
    pass

inst= toy()

class inhtoy():
    def __new__(cls,obj):
        def __repr__(self):
            return 'Sucessful'
        import types
        obj.__repr__ = types.MethodType(__repr__,obj)
        return obj

t = inhtoy(inst)

实际上,如果我调用t.repr(),它会起作用,但它不会覆盖原来的repr。它显示为<bound method inhtoy.__new__.<locals>.__repr__ of <__main__.toy object at 0x7f76e0b61f98>>这是一种本地方法。
调用 repr(t) 仍然指向原始表示形式 '<__main__.toy object at 0x7f76e0b61f98>' 而不是被覆盖的那个。

有没有正确的方法可以做到这一点?
谢谢


即使他们的 __repr__ 看起来很糟糕,但用自己的替代品替换它将会更加令人困惑。 - user2357112
虽然我也想知道如何在实例运行时做到这一点,但为什么不子类化他们的类并只更改__repr__呢? - Nullman
@Nullman 因为子类化需要用户继承它。这也会改变类名生成,导致与第三方库不兼容。修改对象可以保持一切不变。 - Juan Felipe
4个回答

3

@Nullman的回答有效,因为他们的解决方案实际上是更改类对象toy,而不是像你的方法一样更改实例本身。

特殊属性__class__引用一个实例所属的类对象。

print(t.__class__ is toy) # True

因此,t.__class__.__repr__ = my_custom_repr 将赋值给类 toy 上的 __repr__,而不是实例 t 上的 __repr__
当比较你的方法和 Nullman 的方法时,通过比较 print(t.__repr__) 的输出结果可以看到这一点。假设一个模块级函数 __repr__ 如下所示:
def __repr__(self):
    return repr(self.__class__)

你的解决方案显示:
<bound method __repr__ of <__main__.toy object at 0x00000000029E5A90>>

注意,它显示为__main__.toy object。Nullman的解决方案显示如下:
<bound method __repr__ of <class '__main__.toy'>>

当您使用您的方法调用t.__repr__()时,您调用了在实例t上设置的方法,因此它返回您所做的内容;在您的示例中为字符串Success
然而,当使用repr()时,定义输出:

一个类可以通过定义__repr__()方法来控制其实例返回的内容。

正如Nullman所指出的那样,他们的方法将改变所有现有的toy实例化的未来对象的行为。


关于您的代码使用时,指定方法显示奇怪的名称:
<bound method inhtoy.__new__.<locals>.__repr__ of <__main__.toy object at 0x7f76e0b61f98>>

...这是函数对象的限定名称,来自于__qualname__特殊属性。它是你的类inhtoy的方法__new__本地作用域中的函数__repr__
顺便提一下,通过你的inhtoy类的魔法方法__new__将实例inst传递并没有实际意义。你的代码在功能上等同于:

def __repr__(self):
    return "Success"

inst.__repr__ = types.MethodType(__repr__, obj)

2

经过一番搜索,我找到了this的答案。在实例中执行该操作的方法如下:

t.__class__.__repr__ = my_custom_repr

请注意,这将更改所有的类实例,而不仅仅是此实例。

嗯,对于我的目的来说,它可以工作。你有什么见解为什么它会那样工作吗? - Juan Felipe
很遗憾,我不知道,但如果你弄清楚了,我会很高兴如果你告诉我。 - Nullman
1
@Nullman,我添加了一个答案,试图解释为什么你的解决方案有效而OP的解决方案无效;如果你还有兴趣... - shmee

1
使用一个子类并将其分配给从库获取的实例,就像这样:

class Toy():
    pass
inst = Toy()  # from 3rd party library

class Toy_MyRepr(Toy):
    def __repr__(self):
        return '<my repr of Toy instance >'

inst.__class__ = Toy_MyRepr

1
你可以使用继承来创建一个从感兴趣的类派生出来的新类,然后覆盖repr方法。
class inhtoy(toy):

    def __init__(self):
        toy.__init__(self)

    def __repr__(self):
        # Your repr method

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接