2010-08-24 8 views
6

Estoy luchando con la conversión de impresión y Unicode. Aquí hay algún código ejecutado en el intérprete de Windows 2.5.Imprimir objetos y unicode, ¿qué hay debajo del capó? ¿Cuáles son las buenas pautas?

>>> import sys 
>>> print sys.stdout.encoding 
cp850 
>>> print u"é" 
é 
>>> print u"é".encode("cp850") 
é 
>>> print u"é".encode("utf8") 
├® 
>>> print u"é".__repr__() 
u'\xe9' 

>>> class A(): 
... def __unicode__(self): 
...  return u"é" 
... 
>>> print A() 
<__main__.A instance at 0x0000000002AEEA88> 

>>> class B(): 
... def __repr__(self): 
...  return u"é".encode("cp850") 
... 
>>> print B() 
é 

>>> class C(): 
... def __repr__(self): 
...  return u"é".encode("utf8") 
... 
>>> print C() 
├® 

>>> class D(): 
... def __str__(self): 
...  return u"é" 
... 
>>> print D() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 0: ordinal not in range(128) 

>>> class E(): 
... def __repr__(self): 
...  return u"é" 
... 
>>> print E() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 0: ordinal not in range(128) 

lo tanto, cuando se imprime una cadena Unicode, no es que es __repr__() función que se llama y se imprime.
Pero cuando se imprime un objeto o __str__()__repr__() (si __str__ no implementado) se llama, no __unicode__(). Ambos no pueden devolver una cadena Unicode.
¿Pero por qué? ¿Por qué si __repr__() o __str__() devuelven una cadena Unicode, ¿no debería ser el mismo comportamiento que cuando imprimimos una cadena Unicode? En otras palabras: ¿por qué print D() es diferente de print D().__str__()

¿E-candole algo?

Estas muestras también muestran que si desea imprimir un objeto representado con cadenas Unicode, hay que codificar a una cadena de objetos (tipo str). Pero para una buena impresión (evite el "├®"), depende de la codificación sys.stdout.
Por lo tanto, tengo que añadir u"é".encode(sys.stdout.encoding) para cada uno de mi método __str__ o __repr__? ¿O devolver repr (u "é")? ¿Qué sucede si uso tuberías? ¿Es la misma codificación que sys.stdout?

Mi problema principal es hacer una clase de "imprimir", es decir print A() imprime algo totalmente legible (no con los \ x *** caracteres Unicode). Aquí es el mal comportamiento/código que necesita ser modificado:

class User(object): 
    name = u"Luiz Inácio Lula da Silva" 
    def __repr__(self): 
     # returns unicode 
     return "<User: %s>" % self.name 
     # won't display gracefully 
     # expl: print repr(u'é') -> u'\xe9' 
     return repr("<User: %s>" % self.name) 
     # won't display gracefully 
     # expl: print u"é".encode("utf8") -> print '\xc3\xa9' -> ├® 
     return ("<User: %s>" % self.name).encode("utf8") 

Gracias!

Respuesta

8

Python no tiene muchas restricciones de tipo semántico sobre las funciones y métodos dados, pero tiene algunos , y aquí está uno de ellos: __str__ (en Python 2. *) debe devolver una cadena de bytes. Como es habitual, si se encuentra un objeto Unicode donde se requiere una cadena de bytes, se aplica la codificación predeterminada actual (generalmente 'ascii') en el intento de crear la cadena de bytes requerida del objeto Unicode en cuestión.

Para esta operación, la codificación (si existe) de cualquier objeto de archivo dado es irrelevante, porque lo que se devuelve desde __str__ puede estar a punto de imprimirse, o puede estar sujeto a un tratamiento completamente diferente y no relacionado. Su propósito al llamar al __str__ no le importa a la llamada en sí y sus resultados; Python, en general, no tiene en cuenta el "contexto futuro" de una operación (lo que va a hacer con el resultado una vez finalizada la operación) para determinar la semántica de la operación.

Eso es porque Python no siempre sabe sus intenciones futuras, y trata de minimizar la cantidad de sorpresa.print str(x) y s = str(x); print s (las mismas operaciones que se realizan de un trago vs dos), en particular, deben tener los mismos efectos; si el segundo caso, habrá una excepción si str(x) no puede producir válidamente una cadena de bytes (es decir, por ejemplo, x.__str__() no puede), y por lo tanto la excepción debería también se producen en el otro caso.

print sí (ya que 2.4, creo), cuando se le presenta un objeto Unicode, tiene en cuenta el atributo .encoding (si lo hay) de la corriente de destino (por defecto sys.stdout); otras operaciones, como todavía no conectado a cualquier corriente de diana dada, NO - y str(x) (es decir x.__str__()) es sólo una operación de este tipo.

la esperanza que esto ayudó a mostrar la razón de la conducta que es molesto que ...

Editar: el OP ahora aclara "Mi problema principal es hacer una clase de 'imprimir', es decir, la impresión A() imprime algo completamente legible (no con los caracteres unicode \ x ***). ". Aquí está el enfoque creo que funciona mejor para ese objetivo específico:

import sys 

DEFAULT_ENCODING = 'UTF-8' # or whatever you like best 

class sic(object): 

    def __unicode__(self): # the "real thing" 
     return u'Pel\xe9' 

    def __str__(self):  # tries to "look nice" 
     return unicode(self).encode(sys.stdout.encoding or DEFAULT_ENCODING, 
            'replace') 

    def __repr__(self):  # must be unambiguous 
     return repr(unicode(self)) 

Es decir, este enfoque se centra en __unicode__ como la forma primaria para las instancias de la clase para dar formato a sí mismos - pero ya que (en Python 2) print llama __str__ en cambio, tiene ese delegado a __unicode__ con lo mejor que puede hacer en términos de codificación. No es perfecto, pero la declaración de print de Python 2 está lejos de ser perfecta ;-).

__repr__, por su parte, debe esforzarse por ser inequívoco, es decir, no a "mirar bien" a costa de poner en riesgo la ambigüedad (idealmente, cuando sea posible, se debe devolver una cadena de bytes que, si pasó a eval, haría una instancia igual a la actual ... eso está lejos de siempre es factible, pero la falta de ambigüedad es la absoluta núcleo de la distinción entre __str__ y __repr__, y yo fuertemente recomiendan respetar esa distinción !).

+0

Gracias Alex, ahora veo por qué 'D de impresión()' tiene un comportamiento diferente de 'impresión D() .__ str __()'. Fue un poco confuso Entonces, ¿podría compartir alguna guía cuando necesite manejar cadenas unicode en los métodos __repr__ o __str__? ¿Debo devolver un repr() de todo el Unicode o codificarlo en un objeto de cadena? O aún podría devolver un código unicode y establecer la codificación con sys.setdefaultencoding en un módulo de sitio personalizado (pero me pareció demasiado intrusivo). – Thorfin

+0

@Thorfin, para devolver Unicode, implemente '__unicode__'. '__str__' siempre debe devolver una cadena de bytes, y' __repr__' una cadena de bytes que "idealmente" (pero eso no siempre es posible o razonable) uno podría 'eval' para construir un nuevo objeto. –

+0

Creo que '__unicode__' solo se llama junto con unicode(), y desafortunadamente eso no soluciona mis problemas. He agregado información al final del cuerpo de mi pregunta inicial. Gracias de nuevo. – Thorfin

0

que presumen su sys.getdefaultencoding() es todavía 'ascii'. Y creo que esto se está utilizando cada vez que se aplican str() o repr() de un objeto. Puede cambiar eso con sys.setdefaultencoding(). No obstante, tan pronto como escribe en una secuencia, ya sea STDOUT o un archivo, debe cumplir con su codificación. Esto también se aplicaría a la tubería en el caparazón, IMO. Supongo que 'print' respeta la codificación STDOUT, pero la excepción ocurre antes de invocar 'print', al construir su argumento.

Cuestiones relacionadas