Python __str__ versus __unicode__


213

Gibt es eine Python - Konvention für , wenn Sie implementieren sollten __str__()gegenüber __unicode__(). Ich habe gesehen, dass Klassen __unicode__()häufiger überschrieben werden als, __str__()aber es scheint nicht konsistent zu sein. Gibt es bestimmte Regeln, wenn es besser ist, eine gegen die andere zu implementieren? Ist es notwendig / gute Praxis, beide umzusetzen?

Antworten:


257

__str__()ist die alte Methode - sie gibt Bytes zurück. __unicode__()ist die neue, bevorzugte Methode - sie gibt Zeichen zurück. Die Namen sind etwas verwirrend, aber in 2.x bleiben wir aus Kompatibilitätsgründen bei ihnen. Im Allgemeinen sollten Sie alle Ihre Zeichenfolgenformatierungen eingeben __unicode__()und eine Stub- __str__()Methode erstellen :

def __str__(self):
    return unicode(self).encode('utf-8')

strEnthält in 3.0 Zeichen, daher werden die gleichen Methoden benannt __bytes__()und __str__(). Diese verhalten sich wie erwartet.


2
Meinst du damit, sowohl Unicode- als auch Str- Methoden zu erstellen oder nur Strings in _ (u "") zu belassen und einen String zu erstellen (ohne die Unicode-Methode)?
Muntu

12
Gibt es eine Gefahr, nur einen von ihnen zu implementieren? Was passiert, wenn Sie nur implementieren __unicode__und dann tun str(obj)?
RickyA

9
unicodelöst ein NameErrorauf Python 3 aus, ist ein einfaches Muster, das sowohl für 2 als auch für 3 funktioniert?
Bradley.ayers

1
@ bradley.ayers Das futurePaket bietet auch python_2_unicode_compatibleohne Django als Abhängigkeit.
Monkpit

1
Es hängt davon ab, ob. Weil Python3 nicht Unicode verwendet, sondern str ;) für Python 2 Unicode
Eddwin Paz

23

Wenn mir die mikrooptimierende Stringifizierung für eine bestimmte Klasse nicht besonders wichtig wäre, würde ich sie immer implementieren __unicode__ nur , da dies allgemeiner ist. Wenn ich mich um so winzige Leistungsprobleme kümmere (was die Ausnahme und nicht die Regel ist), __str__kann es sein , dass ich nur (wenn ich nachweisen kann, dass die String-Ausgabe niemals Nicht-ASCII-Zeichen enthält) oder beides (wenn beide möglich sind) Hilfe.

Ich denke, dies sind solide Prinzipien, aber in der Praxis ist es sehr üblich zu WISSEN, dass es nur ASCII-Zeichen gibt, ohne sich darum zu bemühen, dies zu beweisen (z. B. enthält die Zeichenfolge nur Ziffern, Satzzeichen und möglicherweise einen kurzen ASCII-Namen ;-), in dem In diesem Fall ist es recht typisch, direkt zum "gerechten __str__" Ansatz überzugehen (aber wenn ein Programmierteam, mit dem ich zusammengearbeitet habe, eine lokale Richtlinie vorschlägt, um dies zu vermeiden, würde ich +1 für den Vorschlag erhalten, da es in diesen Angelegenheiten leicht ist, Fehler zu machen UND "Vorzeitige Optimierung ist die Wurzel allen Übels in der Programmierung" ;-).


2
In Python 2.6.2 wurde ich kürzlich ausgelöst, weil Instanzen einer bestimmten integrierten Exception-Unterklasse mit str (e) und Unicode (e) unterschiedliche Ergebnisse lieferten. str (e) gab benutzerfreundliche Ausgabe; Unicode (e) ergab eine andere, benutzerunfreundliche Ausgabe. Wird dies als fehlerhaftes Verhalten angesehen? Die Klasse ist UnicodeDecodeError; Ich habe es nicht im Voraus benannt, um Verwirrung zu vermeiden - die Tatsache, dass die Ausnahme Unicode-bezogen ist, ist nicht besonders relevant.
Paul Du Bois

13

Wenn die Welt kleiner wird, besteht die Möglichkeit, dass jede Zeichenfolge, auf die Sie stoßen, irgendwann Unicode enthält. Für neue Apps sollten Sie also zumindest bereitstellen __unicode__(). Ob Sie auch überschreiben, __str__()ist dann nur Geschmackssache.


8

Wenn Sie in Django sowohl in Python2 als auch in Python3 arbeiten, empfehle ich den Dekorator python_2_unicode_compatible:

Django bietet eine einfache Möglichkeit, str () - und unicode () -Methoden zu definieren , die unter Python 2 und 3 funktionieren: Sie müssen eine str () -Methode definieren, die Text zurückgibt, und den Dekorator python_2_unicode_compatible () anwenden.

Wie in früheren Kommentaren zu einer anderen Antwort erwähnt, unterstützen einige Versionen von future.utils auch diesen Dekorateur. Auf meinem System musste ich ein neueres zukünftiges Modul für Python2 und Future für Python3 installieren. Danach ist hier ein Funktionsbeispiel:

#! /usr/bin/env python

from future.utils import python_2_unicode_compatible
from sys import version_info

@python_2_unicode_compatible
class SomeClass():
    def __str__(self):
        return "Called __str__"


if __name__ == "__main__":
    some_inst = SomeClass()
    print(some_inst)
    if (version_info > (3,0)):
        print("Python 3 does not support unicode()")
    else:
        print(unicode(some_inst))

Hier ist eine Beispielausgabe (wobei venv2 / venv3 virtuelle Instanzen sind):

~/tmp$ ./venv3/bin/python3 demo_python_2_unicode_compatible.py 
Called __str__
Python 3 does not support unicode()

~/tmp$ ./venv2/bin/python2 demo_python_2_unicode_compatible.py 
Called __str__
Called __str__

3

Python 2: Implementieren Sie nur __str __ () und geben Sie einen Unicode zurück.

Wenn __unicode__()weggelassen wird und jemand unicode(o)oder anruft u"%s"%o, ruft Python auf o.__str__()und konvertiert mithilfe der Systemcodierung in Unicode. (Siehe Dokumentation von__unicode__() .)

Das Gegenteil ist nicht der Fall. Wenn Sie implementieren, __unicode__()aber nicht __str__(), kehrt Python zurück , wenn jemand str(o)oder anruft ."%s"%orepr(o)


Begründung

Warum sollte es funktionieren, ein unicodevon zurückzugeben __str__()?
Wenn __str__()ein Unicode zurückgegeben wird, konvertiert Python ihn automatisch in strdie Systemcodierung.

Was ist der Vorteil?
① Sie müssen sich keine Gedanken über die Systemcodierung machen (z. B. locale.getpreferredencoeding(…)). Das ist nicht nur persönlich chaotisch, sondern ich denke, es ist etwas, um das sich das System sowieso kümmern sollte. ② Wenn Sie vorsichtig sind, ist Ihr Code möglicherweise mit Python 3 kompatibel, in dem __str__()Unicode zurückgegeben wird.

Ist es nicht trügerisch, einen Unicode von einer aufgerufenen Funktion zurückzugeben __str__()?
Ein wenig. Möglicherweise tun Sie dies jedoch bereits. Wenn Sie from __future__ import unicode_literalsoben in Ihrer Datei stehen, besteht eine gute Chance, dass Sie einen Unicode zurückgeben, ohne es zu wissen.

Was ist mit Python 3?
Python 3 wird nicht verwendet __unicode__(). Wenn Sie jedoch __str__()so implementieren , dass Unicode unter Python 2 oder Python 3 zurückgegeben wird, ist dieser Teil Ihres Codes kreuzkompatibel.

Was ist, wenn ich mich unicode(o)wesentlich von unterscheiden möchte str()?
Implementieren Sie sowohl __str__()(möglicherweise zurückgegeben str) als auch __unicode__(). Ich stelle mir vor, dass dies selten vorkommt, aber Sie möchten möglicherweise eine wesentlich andere Ausgabe (z. B. ASCII-Versionen von Sonderzeichen, wie ":)"z u"☺". B. für ).

Mir ist klar, dass einige dies kontrovers finden.


1

Es lohnt sich, diejenigen, die mit der __unicode__Funktion nicht vertraut sind, auf einige der Standardverhaltensweisen hinzuweisen, die sie in Python 2.x umgeben, insbesondere wenn sie nebeneinander definiert werden __str__.

class A :
    def __init__(self) :
        self.x = 123
        self.y = 23.3

    #def __str__(self) :
    #    return "STR      {}      {}".format( self.x , self.y)
    def __unicode__(self) :
        return u"UNICODE  {}      {}".format( self.x , self.y)

a1 = A()
a2 = A()

print( "__repr__ checks")
print( a1 )
print( a2 )

print( "\n__str__ vs __unicode__ checks")
print( str( a1 ))
print( unicode(a1))
print( "{}".format( a1 ))
print( u"{}".format( a1 ))

ergibt die folgende Konsolenausgabe ...

__repr__ checks
<__main__.A instance at 0x103f063f8>
<__main__.A instance at 0x103f06440>

__str__ vs __unicode__ checks
<__main__.A instance at 0x103f063f8>
UNICODE 123      23.3
<__main__.A instance at 0x103f063f8>
UNICODE 123      23.3

Nun, wenn ich die __str__Methode auskommentiere

__repr__ checks
STR      123      23.3
STR      123      23.3

__str__ vs __unicode__ checks
STR      123      23.3
UNICODE  123      23.3
STR      123      23.3
UNICODE  123      23.3
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.