Розглянемо цей клас:
class foo(object):
pass
Представлення рядків за замовчуванням виглядає приблизно так:
>>> str(foo)
"<class '__main__.foo'>"
Як я можу зробити цей дисплей користувацьким рядком?
Розглянемо цей клас:
class foo(object):
pass
Представлення рядків за замовчуванням виглядає приблизно так:
>>> str(foo)
"<class '__main__.foo'>"
Як я можу зробити цей дисплей користувацьким рядком?
Відповіді:
Реалізація __str__()
або __repr__()
в метакласі класу.
class MC(type):
def __repr__(self):
return 'Wahaha!'
class C(object):
__metaclass__ = MC
print C
Використовуйте, __str__
якщо ви маєте на увазі читабельну строфікацію, використовуйте __repr__
для однозначних уявлень.
_representation
у тіло класу, так і return self._representation
в __repr__()
методі метакласу.
__repr__
представлення C
. Альтернативою _representation
члену є створення фабрики метакласу, яка виробляє метаклас з належним __repr__
(це може бути добре, якщо ви багато використовуєте).
class foo(object):
def __str__(self):
return "representation"
def __unicode__(self):
return u"representation"
instances
класу, а не для самого класу.
Якщо вам потрібно вибрати __repr__
або __str__
перейти на перший, як за замовчуванням __str__
виклики впровадження, __repr__
коли це не було визначено.
Приклад користувальницького Vector3:
class Vector3(object):
def __init__(self, args):
self.x = args[0]
self.y = args[1]
self.z = args[2]
def __repr__(self):
return "Vector3([{0},{1},{2}])".format(self.x, self.y, self.z)
def __str__(self):
return "x: {0}, y: {1}, z: {2}".format(self.x, self.y, self.z)
У цьому прикладі repr
знову повертається рядок, який можна безпосередньо споживати / виконувати, тоді str
як корисніший як вихід налагодження.
v = Vector3([1,2,3])
print repr(v) #Vector3([1,2,3])
print str(v) #x:1, y:2, z:3
__repr__
vs __str__
є правильною, це не відповідає дійсному питанню, що стосується об'єктів class, а не екземплярів.
Відповідна відповідь Ігнасіо Васкеса-Абрамса цілком правильна. Однак це покоління Python 2. Оновленням для поточного Python 3 буде:
class MC(type):
def __repr__(self):
return 'Wahaha!'
class C(object, metaclass=MC):
pass
print(C)
Якщо ви хочете код, який працює через Python 2 та Python 3, ви охопили шість модулів:
from __future__ import print_function
from six import with_metaclass
class MC(type):
def __repr__(self):
return 'Wahaha!'
class C(with_metaclass(MC)):
pass
print(C)
Нарешті, якщо у вас є один клас, у якому ви хочете мати спеціальний статичний репр, підхід на основі класу вище працює. Але якщо їх декілька, вам доведеться генерувати метаклас, подібний до MC
кожного, і це може набриднути. У такому випадку, якщо зробити ваш метапрограмування ще на крок і створити фабрику метакласу, це стає дещо більш чистим:
from __future__ import print_function
from six import with_metaclass
def custom_class_repr(name):
"""
Factory that returns custom metaclass with a class ``__repr__`` that
returns ``name``.
"""
return type('whatever', (type,), {'__repr__': lambda self: name})
class C(with_metaclass(custom_class_repr('Wahaha!'))): pass
class D(with_metaclass(custom_class_repr('Booyah!'))): pass
class E(with_metaclass(custom_class_repr('Gotcha!'))): pass
print(C, D, E)
відбитки:
Wahaha! Booyah! Gotcha!
Метапрограмування - це не те, що вам зазвичай потрібно щодня, але коли вам це потрібно, воно дійсно потрапляє на місце!
Просто додаю до всіх тонких відповідей мою версію з прикрасою:
from __future__ import print_function
import six
def classrep(rep):
def decorate(cls):
class RepMetaclass(type):
def __repr__(self):
return rep
class Decorated(six.with_metaclass(RepMetaclass, cls)):
pass
return Decorated
return decorate
@classrep("Wahaha!")
class C(object):
pass
print(C)
stdout:
Wahaha!
Нижні сторони:
C
без суперкласу (ні class C:
)C
екземпляри будуть екземплярами якоїсь дивної деривації, тому, ймовірно, буде хорошою ідеєю додати також і __repr__
для екземплярів.