正确编写具有继承性的__repr__函数的方法

25

我正在尝试使用面向对象的python编程,并且对于__repr__函数的继承有些不确定。因为父类的函数看起来是这样的:

def __repr__(self):
    '''Returns representation of the object'''
    return("{}({!r})".format("Class name", self._param))

我想知道是否更好地采用一种通用方法(也适用于子类),例如以下方法:

def __repr__(self):
    '''Returns representation of the object'''
    return("{}({!r})".format(self.__class__.__name__, self._param))

是否在每个类中重写函数是一种良好的实践还是需要考虑呢?

此外,请忽略编码部分,因为我将其留下。


2
一般来说,如果你不想扩展方法,覆盖该方法是可以的。 - GIZ
如果所有子类都有 _param 属性,那么它们从父类继承 __repr__ 是相当安全的。 - PM 2Ring
2个回答

18

在Python的数据模型中,__repr__有着特殊的意义:

object.__repr__(self)

repr()内置函数通过调用此方法来计算对象的“官方”字符串表示形式。如果可能的话,这应该看起来像一个有效的Python表达式,可以在适当的环境中使用它重新创建具有相同值的对象。如果不可能,应返回一个类似于<...某些有用描述...>的字符串。返回值必须是一个字符串对象。如果一个类定义了__repr__()但没有定义__str__(),那么在需要该类实例的“非正式”字符串表示时也会使用__repr__()

通常用于调试,因此表示应具有丰富的信息和无歧义性。

这意味着由__repr__返回的字符串应该可用于创建另一个完全相同的对象。因此,__repr__通常需要重写,不是因为__class__.__name__,而是因为需要在表示中捕获“状态”。

class A(object):
    def __init__(self, param):
        self._param = param

    def __repr__(self):
        '''Returns representation of the object'''
        return("{}({!r})".format(self.__class__.__name__, self._param))

如果您在__init__中添加参数,那么绝对应该覆盖__repr__

class B(A):
    def __init__(self, param1, param2):
        self._param = param1
        self._param2 = param2

    def __repr__(self):
        '''Returns representation of the object'''
        return("{}({!r})".format(self.__class__.__name__, self._param, self._param2))

但是如果超类的__repr__仍然准确地描述了子类,那么重载__repr__就没有意义:

class B(A):
     pass

然而,使用self.__class__.__name__总是一个好的选择,而不是硬编码类名,以防您或其他人对其进行子类化。


3
对于根据其repr建议来重新创建对象的能力,您应该持保留态度:这对某些类型的对象非常有效,但它是在Python的input函数在用户键入值时调用"eval"的时代提出的,因此它是针对Python语言的交互使用的另一种思维方式。根据对象的类型,这种repr工作方式并不实用,有时甚至不可取。 - jsbueno
1
@jsbueno 对于调试(以及在StackOverflow上发布时)来说,这更为重要。当表示包含定义实例的所有必要信息时,重新创建特定状态或“查看”正在发生的情况就变得更加容易。 - MSeifert
我认为type(self).__name__是更好的选择作为__repr__,因为它给出了self真实类名——在使用repr进行调试时所需的内容——这可能与其虚拟类名不同,通常用于代理对象,例如由weakref.proxy返回的对象(参见我的回答)。 - Géry Ogam

2

是的——这不仅仅是“可以”,而且在几乎每个项目和类层次结构中,这更加实用。

事实上,这几乎是一个完美的“教科书例子”:何时使用类继承,并且只需重复使用超类中的代码。


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