Can I define a __repr__ for a class rather than an instance? [duplicate]

爱⌒轻易说出口 提交于 2019-12-30 17:23:31

问题


Can I define a __repr__ for a class rather than an instance? For example, I'm trying to do this

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

What I get is

In [58]: a=A()

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

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

I'm trying to get the output of line 60 to look like "My Class A", not for the instance a. The reason I want to do this is I'm generating a lot of classes using Python's metaclass. And I want a more readable way to identify the class than the stock repr.


回答1:


You need to define __repr__ on the metaclass.

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

class A(object):
    __metaclass__ = Meta

__repr__ returns a representation of an instance of an object. So by defining __repr__ on A, you're specifying what you want repr(A()) to look like.

To define the representation of the class, you need to define how an instance of type is represented. In this case, replace type with a custom metaclass with __repr__ defined as you need.

>> repr(A)
My class A

If you want to define a custom __repr__ for each class, I'm not sure there's a particularly clean way to do it. But you could do something like this.

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

Then you can customize on a per-class basis.

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



回答2:


Can I define a __repr__ for a class rather than an instance?

Sure, I demonstrate here, with a __repr__ that passes the repr test.

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__)

And to demonstrate:

class Foo(object): pass

class Bar(object): pass

Either Python 2:

class Baz(Foo, Bar): 
    __metaclass__ = Type

Or Python 3:

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

Or fairly universally:

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

And to do the repr test:

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

What is the repr test? It's the above test from the documentation on 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.


来源:https://stackoverflow.com/questions/8955754/can-i-define-a-repr-for-a-class-rather-than-an-instance

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!