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

2 11

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.