2009-08-20 4 views
182

Esiste una convenzione python per quando è necessario implementare __str__() rispetto a __unicode__(). Ho visto le classi ignorare __unicode__() più frequentemente di __str__() ma non sembra coerente. Esistono regole specifiche quando è meglio implementare l'una rispetto all'altra? È necessario/buona pratica implementare entrambi?Python __str__ rispetto a __unicode__

risposta

227

__str__() è il vecchio metodo - restituisce i byte. __unicode__() è il nuovo metodo preferito, che restituisce i caratteri. I nomi sono un po 'confusi, ma in 2.x siamo bloccati con loro per motivi di compatibilità. In generale, si dovrebbe mettere tutta la stringa di formattazione in __unicode__(), e creare uno stub __str__() metodo:

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

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

+1

sa che intendi creare entrambi i metodi __unicode__ e __str__ o semplicemente mantenere le stringhe in _ (u "") e creare __string__ (senza il metodo unicode)? – muntu

+9

C'è qualche trappola nell'implementazione di uno solo di essi? Cosa succede quando implementate solo "__unicode__" e poi "str (obj)"? – RickyA

+9

'unicode' solleva un' NameError' su Python 3, è un pattern semplice che funziona sia su 2 che su 3? –

9

Con il mondo sempre più piccolo, è probabile che qualsiasi stringa che incontrerai conterrà infine Unicode. Quindi, per qualsiasi nuova app, dovresti almeno fornire __unicode__(). Se si sostituisce anche __str__() è solo una questione di gusti.

19

Se non mi interessasse particolarmente l'ottimizzazione delle micro-ottimizzazioni per una determinata classe, implementerei sempre __unicode__, in quanto è più generale. Quando mi preoccupo di problemi di prestazioni così minuti (che è l'eccezione, non la regola), avendo solo __str__ (quando posso provare che non ci saranno mai caratteri non ASCII nell'output con stringhe) o entrambi (quando entrambi sono possibili), potrebbe aiutare.

Questi penso siano solidi principi, ma in pratica è molto comune SAPERE che non ci saranno nient'altro che caratteri ASCII senza fare alcuno sforzo per dimostrarlo (ad es. La forma stringificata ha solo cifre, punteggiatura e forse un breve nome ASCII; -) nel qual caso è abbastanza tipico passare direttamente all'approccio "just __str__" (ma se un team di programmazione con cui ho lavorato ha proposto una linea guida locale per evitarlo, sarei +1 sulla proposta, poiché è facile err in queste materie E "l'ottimizzazione prematura è la radice di tutto il male nella programmazione" ;-).

+2

in Python 2.6.2, ho recentemente ottenuto sgambetto perché le istanze di una particolare sottoclasse Exception incorporata ha dato risultati diversi con str (e) e unicode (e). str (e) ha dato un output user-friendly; unicode (e) ha dato un output diverso, user-unfriendly. Si considera un comportamento bacato? La classe è UnicodeDecodeError; Non l'ho chiamato in primo piano per evitare confusione - il fatto che l'eccezione sia correlata all'unicode non è particolarmente rilevante. –

0

Se si sta lavorando sia in python2 e python3 in Django, vi consiglio il decoratore python_2_unicode_compatible:

Django fornisce un modo semplice per definire str() e unicode() metodi che funzionano su Python 2 e 3: è necessario definire un metodo str() per restituire 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 future per python3. Dopo di che, quindi 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 esempio di uscita (dove venv2/venv3 sono casi 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__