Rozważ tę klasę:
class foo(object):
pass
Domyślna reprezentacja ciągu wygląda mniej więcej tak:
>>> str(foo)
"<class '__main__.foo'>"
Jak ustawić wyświetlanie niestandardowego ciągu?
Rozważ tę klasę:
class foo(object):
pass
Domyślna reprezentacja ciągu wygląda mniej więcej tak:
>>> str(foo)
"<class '__main__.foo'>"
Jak ustawić wyświetlanie niestandardowego ciągu?
Odpowiedzi:
Implementuj __str__()
lub __repr__()
w metaklasie klasy.
class MC(type):
def __repr__(self):
return 'Wahaha!'
class C(object):
__metaclass__ = MC
print C
Użyj, __str__
jeśli masz na myśli czytelne oznaczenie, użyj __repr__
do jednoznacznych reprezentacji.
_representation
do ciała klasy i return self._representation
w __repr__()
sposobie metaklasą.
__repr__
reprezentacji C
. Alternatywą dla posiadania _representation
członka jest utworzenie fabryki metaklasy, która produkuje metaklasę z odpowiednią __repr__
(może to być miłe, jeśli często z niej korzystasz).
class foo(object):
def __str__(self):
return "representation"
def __unicode__(self):
return u"representation"
instances
klasę, a nie samą klasę.
Jeśli musisz wybrać między pierwszym __repr__
lub __str__
przejść do pierwszego, domyślnie __str__
wywołuje implementację, __repr__
gdy nie została zdefiniowana.
Przykład niestandardowego 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)
W tym przykładzie repr
ponownie zwraca ciąg, który może być bezpośrednio wykorzystany / wykonany, ale str
jest bardziej przydatny jako wyjście debugowania.
v = Vector3([1,2,3])
print repr(v) #Vector3([1,2,3])
print str(v) #x:1, y:2, z:3
__repr__
vs __str__
jest poprawne, to nie odpowiada na rzeczywiste pytanie, które dotyczy obiektów klasy, a nie instancji.
Zatwierdzona odpowiedź Ignacio Vazquez-Abramsa jest całkiem słuszna. Jest jednak z generacji Python 2. Aktualizacja obecnego obecnie języka Python 3 będzie:
class MC(type):
def __repr__(self):
return 'Wahaha!'
class C(object, metaclass=MC):
pass
print(C)
Jeśli chcesz, aby kod działał zarówno w Pythonie 2, jak i Pythonie 3, sześć modułów obejmuje:
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)
Wreszcie, jeśli masz jedną klasę, w której chcesz mieć niestandardowe statyczne powtórzenie, powyższe podejście oparte na klasach działa świetnie. Ale jeśli masz kilka, musisz wygenerować metaklasę podobną do MC
każdej z nich, a to może być męczące. W takim przypadku pójście o krok dalej i stworzenie fabryki metaklasy sprawi, że wszystko będzie trochę czystsze:
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)
drukuje:
Wahaha! Booyah! Gotcha!
Metaprogramowanie nie jest czymś, czego zwykle potrzebujesz na co dzień - ale kiedy tego potrzebujesz, naprawdę trafia w sedno!
Właśnie dodając do wszystkich dobrych odpowiedzi, moja wersja z dekoracją:
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)
standardowe:
Wahaha!
Wady:
C
bez superklasy (nie class C:
)C
instancje będą instancjami o dziwnym pochodzeniu, więc prawdopodobnie dobrym pomysłem jest dodanie również __repr__
dla instancji.