¿Cómo puedo elegir una representación de cadena personalizada para una clase en sí (no instancias de la clase)?

Resuelto Björn Pollex asked hace 13 años • 7 respuestas

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.

Björn Pollex avatar Feb 08 '11 18:02 Björn Pollex
Aceptado

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)
Ignacio Vazquez-Abrams avatar Feb 08 '2011 11:02 Ignacio Vazquez-Abrams
class foo(object):
    def __str__(self):
        return "representation"
    def __unicode__(self):
        return u"representation"
Andrey Gubarev avatar Feb 08 '2011 11:02 Andrey Gubarev

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, reprdevuelve nuevamente una cadena que se puede consumir/ejecutar directamente, aunque stres 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
user1767754 avatar Jan 12 '2018 08:01 user1767754

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 MCpara 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!

Jonathan Eunice avatar Mar 07 '2019 21:03 Jonathan Eunice