Могу ли я определить __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, чтобы выглядеть как "Мой класс А", а не для экземпляра a. Причина, по которой я хочу это сделать, - это создать много классов с использованием метакласса Python. И я хочу более читаемый способ идентифицировать класс, чем реестр запасов.

Ответ 1

Вам нужно определить __repr__ в метаклассе.

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

class A(object):
    __metaclass__ = Meta

__repr__ возвращает представление экземпляра объекта. Поэтому, определяя __repr__ на A, вы указываете, как вы хотите выглядеть 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>

Ответ 2

Могу ли я определить __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.