Python __str__ contro __unicode__


213

C'è una convenzione python per quando dovresti implementare __str__()contro__unicode__() . Ho visto le classi scavalcare __unicode__()più frequentemente di __str__()ma non sembra coerente. Ci sono regole specifiche quando è meglio implementare l'una rispetto all'altra? È necessaria / buona pratica implementare entrambi?

Risposte:


257

__str__()è il vecchio metodo - restituisce byte. __unicode__()è il nuovo metodo preferito: restituisce caratteri. I nomi sono un po 'confusi, ma in 2.x siamo bloccati con loro per motivi di compatibilità. Generalmente, dovresti inserire tutta la formattazione della stringa __unicode__()e creare un __str__()metodo stub :

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

In 3.0, strcontiene caratteri, quindi gli stessi metodi sono denominati __bytes__()e __str__(). Questi si comportano come previsto.


2
come intendi creare sia metodi unicode che str o semplicemente mantenere le stringhe in _ (u "") e creare una stringa (senza il metodo unicode)?
muntu,

12
C'è qualche insidia nell'attuare solo uno di essi? Cosa succede quando si implementa __unicode__e poi si fa str(obj)?
Ricky,

9
unicodegenera a NameErrorsu Python 3, è un modello semplice che funziona sia su 2 che su 3?
Bradley.ayers,

1
@ bradley.ayers il futurepacchetto fornisce anche python_2_unicode_compatiblesenza avere Django come dipendenza.
Monkpit,

1
Dipende. Perché python3 non usa unicode ma invece str ;) per python 2 unicode
Eddwin Paz,

23

Se non mi interessasse particolarmente la micro-ottimizzazione della stringa per una determinata classe, implementerei sempre __unicode__solo, poiché è più generale. Quando mi preoccupo di problemi di prestazione così piccoli (che è l'eccezione, non la regola), avere __str__solo (quando posso dimostrare che non ci saranno mai caratteri non ASCII nell'output rigoroso) o entrambi (quando entrambi sono possibili), potrebbe Aiuto.

Penso che questi siano principi solidi, ma in pratica è molto comune SAPERE che non ci saranno nient'altro che caratteri ASCII senza fare uno sforzo per dimostrarlo (ad esempio la forma stringita ha solo cifre, punteggiatura e forse un breve nome ASCII ;-) in cui caso è abbastanza tipico passare direttamente __str__all'approccio "giusto " (ma se un team di programmazione con cui ho lavorato ha proposto una linea guida locale per evitarlo, sarei +1 sulla proposta, poiché è facile sbagliare in queste questioni E "l'ottimizzazione prematura è la radice di ogni male nella programmazione" ;-).


2
In Python 2.6.2, mi sono recentemente imbattuto perché le istanze di una particolare sottoclasse Eccezione incorporata hanno dato risultati diversi con str (e) e unicode (e). str (e) ha fornito un output intuitivo; unicode (e) ha fornito un output diverso e poco intuitivo. Questo comportamento è considerato buggy? La classe è UnicodeDecodeError; Non l'ho chiamato in anticipo per evitare confusione: il fatto che l'eccezione sia legata all'unicode non è particolarmente rilevante.
Paul Du Bois,

13

Con il mondo che si restringe, è probabile che qualsiasi stringa che incontri alla fine conterrà Unicode. Quindi, per qualsiasi nuova app, dovresti almeno fornire __unicode__(). Se anche tu hai la precedenza, __str__()è solo una questione di gusti.


8

Se lavori in python2 e python3 in Django, ti consiglio il decoratore python_2_unicode_compatible:

Django fornisce un modo semplice per definire i metodi str () e unicode () che funzionano su Python 2 e 3: è necessario definire un metodo str () che restituisca il testo e applicare il decoratore python_2_unicode_compatible ().

Come notato nei commenti precedenti a un'altra risposta, alcune versioni di future.utils supportano anche questo decoratore. Sul mio sistema, avevo bisogno di installare un nuovo modulo futuro per python2 e installare futuro per python3. Dopodiché, ecco un esempio funzionale:

#! /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))

Ecco un esempio di output (dove venv2 / venv3 sono istanze virtualenv):

~/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: implementa solo __str __ () e restituisce un unicode.

Quando __unicode__()viene omesso e qualcuno chiama unicode(o)o u"%s"%o, Python chiama o.__str__()e si converte in unicode usando la codifica di sistema. (Vedi documentazione di__unicode__() .)

Non è vero il contrario. Se implementate __unicode__()ma non __str__(), quando qualcuno chiama str(o)o "%s"%o, Python ritorna repr(o).


Fondamento logico

Perché dovrebbe funzionare per restituire un unicodeda __str__()?
Se __str__()restituisce un unicode, Python lo converte automaticamente instr usando la codifica del sistema.

Qual è il vantaggio?
① Ti libera dal preoccuparti di quale sia la codifica del sistema (cioè, locale.getpreferredencoeding(…)). Non solo è disordinato, personalmente, ma penso che sia qualcosa di cui il sistema dovrebbe occuparsi comunque. ② Se stai attento, il tuo codice potrebbe risultare compatibile con Python 3, in cui__str__() restituisce Unicode.

Non è ingannevole restituire un unicode da una funzione chiamata __str__()?
Un po. Tuttavia, potresti già farlo. Se haifrom __future__ import unicode_literals nella parte superiore del tuo file, c'è una buona probabilità che tu restituisca un unicode senza nemmeno saperlo.

Che dire di Python 3?
Python 3 non utilizza __unicode__(). Tuttavia, se si implementa__str__() modo tale da restituire Unicode in Python 2 o Python 3, quella parte del codice sarà compatibile con la compatibilità incrociata.

E se volessi unicode(o)essere sostanzialmente diverso da str()?
Implementa entrambi __str__()(possibilmente tornando str) e __unicode__(). Immagino che questo sarebbe raro, ma potresti volere risultati sostanzialmente diversi (ad es. Versioni ASCII di caratteri speciali, come ":)"per u"☺").

Mi rendo conto che alcuni potrebbero trovarlo controverso.


1

Vale la pena sottolineare a coloro che non hanno familiarità con la __unicode__funzione alcuni dei comportamenti predefiniti che lo circondano in Python 2.x, specialmente se definiti fianco a fianco __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 ))

produce il seguente output di console ...

__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

Ora, quando ho decommentato il __str__metodo

__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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.