如何正确实现 __str__ 和 __repr__

Jon*_*ler 5 python

在我的几个类中,我想同时实现__str__和,__repr__并且通常以这样的代码结束:

class MyClass(object):
    def __init__(self, a):
        self.a = a

    def __str__(self):
        return 'MyClass({})'.format(self.a)

    def __repr__(self):
        return 'MyClass({!r})'.format(self.a)
Run Code Online (Sandbox Code Playgroud)

这符合我的期望:

>>> myobject = MyClass(np.array([1, 2]))
>>> str(myobject)
'MyClass([1 2])'
>>> repr(myobject)
'MyClass(array([1, 2]))'
Run Code Online (Sandbox Code Playgroud)

然而,代码违反了 DRY,随着参数数量开始增加,维护这变得很麻烦,我经常发现其中一个__str____repr__已经与另一个“不同步”。

是否有同时实现这两个更好的办法__str__,并__repr__没有重复?

Ara*_*Fey 5

由于您__str____repr__遵循相同的模式,您可以编写一个函数来为您创建对象的字符串表示形式。它需要一个对象、一个属性列表和/strrepr作为参数:

def stringify(obj, attrs, strfunc):
    values = []
    # get each attribute's value and convert it to a string
    for attr in attrs:
        value = getattr(obj, attr)
        values.append(strfunc(value))

    # get the class name
    clsname = type(obj).__name__

    # put everything together
    args = ', '.join(values)
    return '{}({})'.format(clsname, args)

print( stringify(MyClass('foo'), ['a'], repr) )
# output: MyClass('foo')
Run Code Online (Sandbox Code Playgroud)

我建议将此函数放在一个类中,然后您可以从该类继承:

class Printable:
    def __str__(self):
        return self.__stringify(str)

    def __repr__(self):
        return self.__stringify(repr)

    def __stringify(self, strfunc):
        values = []
        for attr in self._attributes:
            value = getattr(self, attr)
            values.append(strfunc(value))

        clsname = type(self).__name__
        args = ', '.join(values)
        return '{}({})'.format(clsname, args)

class MyClass(Printable):
    _attributes = ['a']

    def __init__(self, a):
        self.a = a
Run Code Online (Sandbox Code Playgroud)

你甚至可以通过直接从__init__函数的签名中获取属性来完全自动完成它:

import inspect

class AutoPrintable:
    def __str__(self):
        return self.__stringify(str)

    def __repr__(self):
        return self.__stringify(repr)

    def __stringify(self, strfunc):
        sig= inspect.signature(self.__init__)
        values= []
        for attr in sig.parameters:
            value= getattr(self, attr)
            values.append(strfunc(value))

        clsname= type(self).__name__
        args= ', '.join(values)
        return '{}({})'.format(clsname, args)

class MyClass(AutoPrintable):
    def __init__(self, a, b):
        self.a = a
        self.b = b

print( str(MyClass('foo', 'bar')) ) # output: MyClass(foo, bar)
print( repr(MyClass('foo', 'bar')) ) # output: MyClass('foo', 'bar')
Run Code Online (Sandbox Code Playgroud)


ber*_*erg 2

不需要重复,只是不实施__str__

这样,该对象的行为将类似于__str__ = __repr__.

我想你也应该阅读这个答案