我可以为类而不是实例定义__repr__吗?
我可以为一个类定义一个 __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>