Considera questa classe:
class foo(object):
pass
La rappresentazione di stringa predefinita è simile alla seguente:
>>> str(foo)
"<class '__main__.foo'>"
Come posso rendere questo display una stringa personalizzata?
Considera questa classe:
class foo(object):
pass
La rappresentazione di stringa predefinita è simile alla seguente:
>>> str(foo)
"<class '__main__.foo'>"
Come posso rendere questo display una stringa personalizzata?
Risposte:
Implementa __str__()
o __repr__()
nella metaclasse della classe.
class MC(type):
def __repr__(self):
return 'Wahaha!'
class C(object):
__metaclass__ = MC
print C
Utilizzare __str__
se si intende una stringificazione leggibile, utilizzare __repr__
per rappresentazioni non ambigue.
_representation
al corpo della classe e return self._representation
al __repr__()
metodo della metaclasse.
__repr__
per rappresentare C
. Un'alternativa all'avere un _representation
membro è quella di creare una fabbrica di metaclasse che produca una metaclasse con il corretto __repr__
(questo potrebbe essere utile se lo usi molto).
class foo(object):
def __str__(self):
return "representation"
def __unicode__(self):
return u"representation"
instances
la classe, non per la classe stessa.
Se devi scegliere tra __repr__
o __str__
scegliere il primo, come per impostazione predefinita, l'implementazione __str__
chiama __repr__
quando non è stato definito.
Esempio di Vector3 personalizzato:
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)
In questo esempio, repr
restituisce di nuovo una stringa che può essere consumata / eseguita direttamente, mentre str
è più utile come output di debug.
v = Vector3([1,2,3])
print repr(v) #Vector3([1,2,3])
print str(v) #x:1, y:2, z:3
__repr__
vs __str__
è corretto, questo non risponde alla domanda reale, che riguarda gli oggetti di classe, non le istanze.
La risposta approvata da Ignacio Vazquez-Abrams è assolutamente corretta. È, tuttavia, dalla generazione di Python 2. Un aggiornamento per l'attuale Python 3 sarebbe:
class MC(type):
def __repr__(self):
return 'Wahaha!'
class C(object, metaclass=MC):
pass
print(C)
Se si desidera che il codice venga eseguito su Python 2 e Python 3, il modulo sei è coperto:
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)
Infine, se si dispone di una classe per cui si desidera avere una repr statica personalizzata, l'approccio basato sulla classe sopra funziona alla grande. Ma se ne hai diversi, dovresti generare una metaclasse simile a MC
ciascuno di essi e questo può diventare noioso. In tal caso, fare un passo avanti con la metaprogrammazione e creare una fabbrica di metaclasse rende le cose un po 'più pulite:
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)
stampe:
Wahaha! Booyah! Gotcha!
La metaprogrammazione non è qualcosa di cui di solito hai bisogno ogni giorno, ma quando ne hai bisogno, colpisce davvero il punto!
Aggiungo solo a tutte le belle risposte, la mia versione con decorazioni:
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!
I lati negativi:
C
senza una super classe (no class C:
)C
le istanze saranno istanze di una strana derivazione, quindi è probabilmente una buona idea aggiungere anche una __repr__
per le istanze.