我可以为类而不是实例定义__repr__吗?

14 投票
2 回答
5792 浏览
提问于 2025-04-17 10:47

我可以为一个类定义一个 __repr__ 吗,而不是为它的实例定义?比如,我想这样做:

class A(object):
    @classmethod
    def __repr__(cls):
        return 'My class %s' % cls

我得到的是:

In [58]: a=A()

In [59]: a
Out[59]: My class <class '__main__.A'>

In [60]: A
Out[60]: __main__.A

我想让第60行的输出看起来像 "My Class A",而不是实例 a 的输出。我之所以想这样做,是因为我正在使用 Python 的 metaclass 生成很多类。我希望有一种更易读的方式来识别这些类,而不是使用默认的 repr。

2 个回答

3

我可以为一个类定义一个 __repr__ 而不是为一个实例吗?

当然可以,我在这里演示一下,展示一个通过 repr 测试的 __repr__

class Type(type):
    def __repr__(cls):
        """
        >>> Type('Baz', (Foo, Bar,), {'__module__': '__main__', '__doc__': None})
        Type('Baz', (Foo, Bar,), {'__module__': '__main__', '__doc__': None})
        """
        name = cls.__name__
        parents = ', '.join(b.__name__ for b in cls.__bases__)
        if parents:
            parents += ','
        namespace = ', '.join(': '.join(
          (repr(k), repr(v) if not isinstance(v, type) else v.__name__)) 
               for k, v in cls.__dict__.items())
        return 'Type(\'{0}\', ({1}), {{{2}}})'.format(name, parents, namespace)

    def __eq__(cls, other):
        return (cls.__name__, cls.__bases__, cls.__dict__) == (
                other.__name__, other.__bases__, other.__dict__)

接下来演示一下:

class Foo(object): pass

class Bar(object): pass

可以用 Python 2:

class Baz(Foo, Bar): 
    __metaclass__ = Type

或者用 Python 3:

class Baz(Foo, Bar, metaclass=Type): 
    pass

或者说是比较通用的方式:

Baz = Type('Baz', (Foo, Bar), {})
>>> Baz
Type('Baz', (Foo, Bar,), {'__module__': '__main__', '__doc__': None})

然后进行 repr 测试:

def main():
    print Baz
    assert Baz == eval(repr(Baz))

什么是 repr 测试?就是文档中关于 repr 的上面那个测试:

>>> help(repr)
Help on built-in function repr in module __builtin__:

repr(...)
    repr(object) -> string

    Return the canonical string representation of the object.
    For most object types, eval(repr(object)) == object.
20

你需要在元类上定义 __repr__

class Meta(type):
    def __repr__(cls):
        return 'My class %s' % cls.__name__

class A(object):
    __metaclass__ = Meta

__repr__ 是用来返回一个对象实例的描述的。所以通过在 A 上定义 __repr__,你就是在告诉程序你希望 repr(A()) 看起来是什么样子的。

要定义这个类的描述,你需要说明一个 type 的实例是怎么表示的。在这种情况下,把 type 替换成一个自定义的元类,并在里面定义你需要的 __repr__

>> repr(A)
My class A

如果你想为每个类定义一个自定义的 __repr__,我不太确定有没有特别简单的方法可以做到。不过你可以试试这样做。

class Meta(type):
    def __repr__(cls):
        if hasattr(cls, '_class_repr'):
            return getattr(cls, '_class_repr')()
        else:
            return super(Meta, cls).__repr__()

class A(object):
    __metaclass__ = Meta

    @classmethod
    def _class_repr(cls):
        return 'My class %s' % cls.__name__

class B(object):
    __metaclass__ = Meta

这样你就可以根据每个类进行定制了。

>> repr(A)
My class A
>> repr(B)
<__main__.B object at 0xb772068c>

撰写回答