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

2 ответа

Решение

Вам нужно определить __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>

Могу ли я определить __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.
Другие вопросы по тегам