Wie erstelle ich eine benutzerdefinierte Zeichenfolgendarstellung für ein Klassenobjekt?

202

Betrachten Sie diese Klasse:

class foo(object):
    pass

Die Standarddarstellung der Zeichenfolge sieht ungefähr so ​​aus:

>>> str(foo)
"<class '__main__.foo'>"

Wie kann ich diese Anzeige zu einer benutzerdefinierten Zeichenfolge machen?

Björn Pollex
quelle

Antworten:

272

Implementieren Sie __str__()oder __repr__()in der Metaklasse der Klasse.

class MC(type):
  def __repr__(self):
    return 'Wahaha!'

class C(object):
  __metaclass__ = MC

print C

Verwenden __str__Sie diese Option, wenn Sie eine lesbare Zeichenfolge meinen, __repr__für eindeutige Darstellungen.

Ignacio Vazquez-Abrams
quelle
2
Ich möchte eine Art Klassendekorateur erstellen, damit ich einfach benutzerdefinierte Zeichenfolgendarstellungen für meine Klassen festlegen kann, ohne für jede eine Metaklasse schreiben zu müssen. Ich bin mit Pythons Metaklassen nicht sehr vertraut. Können Sie mir dort also Hinweise geben?
Björn Pollex
Leider ist dies mit Klassendekorateuren nicht möglich. Es muss festgelegt werden, wenn die Klasse definiert wird.
Ignacio Vazquez-Abrams
10
@ Space_C0wb0y: Sie können _representationdem Klassenkörper und return self._representationder __repr__()Methode der Metaklasse eine Zeichenfolge hinzufügen .
Sven Marnach
@ BjörnPollex Vielleicht kannst du das mit dem Dekorateur machen, aber ich würde erwarten, dass du mit vielen Feinheiten der Sprache zu kämpfen hast. Und selbst wenn Sie dies tun, müssen Sie die Metaklasse auf die eine oder andere Weise verwenden, da Sie nicht die Standardeinstellung __repr__für die Darstellung verwenden möchten C. Eine Alternative zu einem _representationMitglied besteht darin, eine Metaklassenfabrik zu erstellen, in der eine Metaklasse mit der richtigen Metaklasse erstellt wird __repr__(dies kann hilfreich sein, wenn Sie diese häufig verwenden).
Skyking
2
@ ThomasLeonard: stackoverflow.com/questions/39013249/metaclass-in-python3-5
Ignacio Vazquez-Abrams
22
class foo(object):
    def __str__(self):
        return "representation"
    def __unicode__(self):
        return u"representation"
Andrey Gubarev
quelle
10
Dies ändert die Zeichenfolgendarstellung für instancesdie Klasse, nicht für die Klasse selbst.
Tauran
Entschuldigung, der zweite Teil Ihres Beitrags wird nicht angezeigt. Verwenden Sie die oben beschriebene Methode.
Andrey Gubarev
6
@ RobertSiemer Warum? Obwohl seine Antwort nicht speziell auf die Frage des OP abzielt, ist sie dennoch hilfreich. Es hat mir geholfen. Und auf einen Blick sehe ich keine Frage nach der Implementierung. Wahrscheinlich landen die Leute zuerst auf dieser Seite.
Akinuri
14

Wenn Sie zwischen dem ersten wählen __repr__oder __str__sich für den ersten entscheiden müssen, wie dies standardmäßig der __str__Fall ist, __repr__wenn die Implementierung nicht definiert wurde.

Beispiel für einen benutzerdefinierten Vektor3:

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 diesem Beispiel wird reprerneut eine Zeichenfolge zurückgegeben, die direkt verwendet / ausgeführt werden kann, während strdies als Debug-Ausgabe nützlicher ist.

v = Vector3([1,2,3])
print repr(v)    #Vector3([1,2,3])
print str(v)     #x:1, y:2, z:3
user1767754
quelle
1
Während Ihr Punkt über __repr__vs __str__richtig ist, beantwortet dies nicht die eigentliche Frage, die sich auf Klassenobjekte und nicht auf Instanzen bezieht.
Björn Pollex
Vielen Dank für das Feedback, das komplett überwacht wurde. Lassen Sie mich meine Antwort überprüfen.
user1767754
Ich denke, Sie Implementierungen für repr und str sind getauscht.
Jspencer
4

Die genehmigte Antwort von Ignacio Vazquez-Abrams ist völlig richtig. Es ist jedoch aus der Python 2-Generation. Ein Update für das jetzt aktuelle Python 3 wäre:

class MC(type):
  def __repr__(self):
    return 'Wahaha!'

class C(object, metaclass=MC):
    pass

print(C)

Wenn Sie Code wünschen, der sowohl in Python 2 als auch in Python 3 ausgeführt wird, haben Sie in den sechs Modulen Folgendes behandelt:

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)

Wenn Sie eine Klasse haben, für die Sie einen benutzerdefinierten statischen Repräsentanten haben möchten, funktioniert der oben beschriebene klassenbasierte Ansatz hervorragend. Wenn Sie jedoch mehrere haben, müssen Sie MCfür jede eine ähnliche Metaklasse generieren , und das kann lästig werden. Wenn Sie in diesem Fall Ihre Metaprogrammierung noch einen Schritt weiter gehen und eine Metaklassenfabrik erstellen, werden die Dinge etwas sauberer:

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)

Drucke:

Wahaha! Booyah! Gotcha!

Metaprogrammierung ist nicht etwas, das Sie normalerweise jeden Tag brauchen - aber wenn Sie es brauchen, ist es genau das Richtige!

Jonathan Eunice
quelle
0

Ich füge nur all die schönen Antworten hinzu, meine Version mit Dekoration:

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!

Die Nachteile:

  1. Sie können nicht Cohne eine Superklasse deklarieren (nein class C:)
  2. CInstanzen sind Instanzen einer seltsamen Ableitung, daher ist es wahrscheinlich eine gute Idee, auch __repr__für die Instanzen eine hinzuzufügen .
Aviv Goll
quelle