¿Cómo puedo elegir una representación de cadena personalizada para una clase en sí (no instancias de la clase)?
Considere esta clase:
class foo(object):
pass
La representación de cadena predeterminada se parece a esto:
>>> str(foo)
"<class '__main__.foo'>"
¿Cómo puedo hacer que esto muestre una cadena personalizada?
Consulte ¿Cómo imprimir instancias de una clase usando print()? para la pregunta correspondiente sobre instancias de la clase.
De hecho, esta pregunta es realmente un caso especial de esa, porque en Python, las clases también son objetos que pertenecen a su propia clase, pero no es directamente obvio cómo aplicar el consejo, ya que la "clase de clases" predeterminada es pre -definido.
Implementar __str__()
o __repr__()
en la metaclase de la clase.
class MC(type):
def __repr__(self):
return 'Wahaha!'
class C(object):
__metaclass__ = MC
print(C)
Úselo __str__
si se refiere a una cadena legible, úselo __repr__
para representaciones inequívocas.
Editar: Versión Python 3
class MC(type):
def __repr__(self):
return 'Wahaha!'
class C(object, metaclass=MC):
pass
print(C)
class foo(object):
def __str__(self):
return "representation"
def __unicode__(self):
return u"representation"
Si tiene que elegir entre __repr__
o __str__
elegir el primero, ya que de forma predeterminada la implementación __str__
llama __repr__
cuando no estaba definido.
Ejemplo de Vector3 personalizado:
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)
En este ejemplo, repr
devuelve nuevamente una cadena que se puede consumir/ejecutar directamente, aunque str
es más útil como salida de depuración.
v = Vector3([1,2,3])
print repr(v) #Vector3([1,2,3])
print str(v) #x:1, y:2, z:3
La respuesta aprobada de Ignacio Vázquez-Abrams es bastante correcta. Sin embargo, es de la generación Python 2. Una actualización para el Python 3 ahora actual sería:
class MC(type):
def __repr__(self):
return 'Wahaha!'
class C(object, metaclass=MC):
pass
print(C)
Si desea código que se ejecute tanto en Python 2 como en Python 3, los seis módulos lo tienen cubierto:
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)
Finalmente, si tiene una clase y desea que tenga una representación estática personalizada, el enfoque basado en clases anterior funciona muy bien. Pero si tienes varias, tendrás que generar una metaclase similar a MC
para cada una, y eso puede resultar tedioso. En ese caso, llevar su metaprogramación un paso más allá y crear una fábrica de metaclases hace que las cosas sean un poco más limpias:
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)
huellas dactilares:
Wahaha! Booyah! Gotcha!
La metaprogramación no es algo que generalmente necesites todos los días, pero cuando la necesitas, ¡realmente da en el clavo!