2011-11-22 9 views
7

Fondamentalmente voglio essere in grado di creare istanze usando una classe chiamata Bottle: ad es. class Bottle(object):... e quindi in un altro modulo essere in grado di "stampare" semplicemente qualsiasi istanza senza dovendo modificare il codice per chiamare esplicitamente una routine di codifica dei caratteri.Python: come forzare una "stampa" per usare __unicode__ invece di __str__, o altrimenti "stampare" il messaggio senza chiamare esplicitamente unicode()

In sintesi, quando provo:

obj=Bottle(u"味精") 
print obj 

o ad un "a posto" "stampa":

print Bottle(u"味精") 

ottengo:

"UnicodeEncodeError: 'ascii' codec can't encode characters" 

domande StackOverflow simili:

¢ Non è attualmente possibile passare python3. ¢

Una soluzione o suggerimento (e spiegazione) su come eseguire una stampa utf-8 sul posto (proprio come la classe U fa con successo di seguito) sarebbe molto apprezzata. :-)

Thanx N

-

codice

Esempio:

-------- 8> < - - - - tagliare qui - - - -

#!/usr/bin/env python 
# -*- coding: utf-8 -*- 

def setdefaultencoding(encoding="utf-8"): 
    import sys, codecs 

    org_encoding = sys.getdefaultencoding() 
    if org_encoding == "ascii": # not good enough 
    print "encoding set to "+encoding 
    sys.stdout = codecs.getwriter(encoding)(sys.stdout) 
    sys.stderr = codecs.getwriter(encoding)(sys.stderr) 

setdefaultencoding() 

msg=u"味精" # the message! 

class U(unicode): pass 

m1=U(msg) 

print "A)", m1 # works fine, even with unicode, but 

class Bottle(object): 
    def __init__(self,msg): self.msg=msg 
    def __repr__(self): 
    print "debug: __repr__",self.msg 
    return '{{{'+self.msg+'}}}' 
    def __unicode__(self): 
    print "debug: __unicode__",self.msg 
    return '{{{'+self.msg+'}}}' 
    def __str__(self): 
    print "debug: __str__",self.msg 
    return '{{{'+self.msg+'}}}' 
    def decode(self,arg): print "debug: decode",self.msg 
    def encode(self,arg): print "debug: encode",self.msg 
    def translate(self,arg): print "debug: translate",self.msg 

m2=Bottle(msg) 

#print "B)", str(m2) 
print "C) repr(x):", repr(m2) 
print "D) unicode(x):", unicode(m2) 
print "E)",m2 # gives: UnicodeEncodeError: 'ascii' codec can't encode characters 

-------- 8> < - - - - tagliare qui - - - - Python 2.4 uscita:

encoding set to utf-8 
A) 味精 
C) repr(x): debug: __repr__ 味精 
{{{\u5473\u7cbe}}} 
D) unicode(x): debug: __unicode__ 味精 
{{{味精}}} 
E) debug: __str__ 味精 
Traceback (most recent call last): 
    File "./uc.py", line 43, in ? 
    print "E)",m2 # gives: UnicodeEncodeError: 'ascii' codec can't encode characters 
UnicodeEncodeError: 'ascii' codec can't encode characters in position 3-4: ordinal not in range(128) 

-------- 8> < - - - - tagliare qui - - - - Python 2.6 uscita:

encoding set to utf-8 
A) 味精 
C) repr(x): debug: __repr__ 味精 
Traceback (most recent call last): 
    File "./uc.py", line 41, in <module> 
    print "C) repr(x):", repr(m2) 
UnicodeEncodeError: 'ascii' codec can't encode characters in position 3-4: ordinal not in range(128) 
+0

l'uscita non riflette il codice esempio, 'repr (x)' 'dovrebbe produrre UnicodeEncodeError' troppo – jfs

+0

@ J.F. Sebastian: Python 2.4 produce quanto sopra, quindi ho eseguito il codice su 2.6 e repr ora produce anche un messaggio di errore. – NevilleDNZ

+0

Il messaggio "UnicodeEncodeError: 'ascii' codec non può codificare i caratteri" mi fa sospettare che "print" non usi "sys.stdout" come ho cambiato il codec/encoding di questo file in "utf-8" con "sys.stdout" = codecs.getwriter (encoding) (sys.stdout) " – NevilleDNZ

risposta

6

se si utilizza sys.stdout = codecs.getwriter(encoding)(sys.stdout) allora si dovrebbe passare stringhe Unicode a print :

>>> print u"%s" % Bottle(u"魯賓遜漂流記") 
debug: __unicode__ 魯賓遜漂流記 
{{{魯賓遜漂流記}}} 

come @bobince sottolinea nei commenti: evitare di modificare sys.stdout nel modo altrimenti potrebbe rompere qualsiasi codice della libreria che funziona con sys.stdout e non si aspetta di stampare le stringhe Unicode.

In generale:

__unicode__() dovrebbe restituire le stringhe Unicode:

def __init__(self, msg, encoding='utf-8'): 
    if not isinstance(msg, unicode): 
     msg = msg.decode(encoding) 
    self.msg = msg 

def __unicode__(self): 
    return u"{{{%s}}}" % self.msg 

__repr__() dovrebbe restituire ascii-friendly str oggetto:

def __repr__(self): 
    return "Bottle(%r)" % self.msg 

__str__() dovrebbe restituire str oggetto. Aggiungi opzionaleencoding per documentare quale codifica viene utilizzata. Non v'è alcun buon modo per scegliere la codifica qui:

def __str__(self, encoding="utf-8") 
    return self.__unicode__().encode(encoding) 

Definire write() metodo:

def write(self, file, encoding=None): 
    encoding = encoding or getattr(file, 'encoding', None) 
    s = unicode(self) 
    if encoding is not None: 
     s = s.encode(encoding) 
    return file.write(s) 

Si dovrebbe coprire i casi in cui il file ha la propria codifica o supporta direttamente stringhe Unicode.

+0

@Robinson Crusoe :-) - Grazie per quello! Vedo anche 'print unicode (Bottle (u" 魯賓遜 漂流 記 ")' funziona. Ma ** stranamente ** l'alternativa ovvia 'print >> sys.stdout, Bottle (u" 魯賓遜 漂流 記 ")' non funziona (anche con il codice 'sys.stdout = codecs.getwriter (" utf-8 ") (sys.stdout)' in alto – NevilleDNZ

+0

Attenzione, anche la codifica dei caratteri del tuo terminale è un fattore importante. l'istruzione 'print' che chiama' __str__', credo che questo sia un bug nell'istruzione 'print' – wberry

+1

State molto attenti a hacking' sys.stdout' per essere un flusso di caratteri invece di un flusso di byte. concetti intercambiabili, quindi cambiarli è fragile: qualsiasi codice libreria che si sta utilizzando che prova a scrivere byte non ASCII su 'sys.stdout' ora fallirebbe, e se stiamo parlando di output sul Prompt dei comandi di Windows, dovresti solo rinunciare ora, non uscirai da Unicode usando le librerie standard di C stdio che usano Python (e la maggior parte delle altre lingue). – bobince

Problemi correlati