2010-09-02 7 views
65

Últimamente, he tenido muchos problemas con __repr__(), format() y codificaciones. ¿Debería codificarse la salida de __repr__() o ser una cadena unicode? ¿Hay una mejor codificación para el resultado de __repr__() en Python? Lo que quiero mostrar tiene caracteres que no sean ASCII.¿El mejor tipo de salida y prácticas de codificación para las funciones __repr __()?

utilizo Python 2.x, y quiero escribir código que puede ser fácilmente adaptado a Python 3. El programa utiliza tanto

# -*- coding: utf-8 -*- 
from __future__ import unicode_literals, print_function # The 'Hello' literal represents a Unicode object 

Éstos son algunos problemas adicionales que me han estado molestando, y yo' m buscando una solución que les resuelve:

  1. impresión a un terminal de UTF-8 debería funcionar (no tengo sys.stdout.encoding conjunto de UTF-8, pero sería mejor si otros casos trabajaron también).
  2. La conexión de la salida a un archivo (codificada en UTF-8) debería funcionar (en este caso, sys.stdout.encoding es None).
  3. Mi código para muchas funciones __repr__() actualmente tiene muchos return ….encode('utf-8'), y eso es pesado. ¿Hay algo robusto y ligero?
  4. En algunos casos, incluso tengo bestias feas como return ('<{}>'.format(repr(x).decode('utf-8'))).encode('utf-8'), es decir, la representación de objetos se decodifica, se pone en una cadena de formato y luego se vuelve a codificar. Me gustaría evitar tales transformaciones enrevesadas.

¿Qué recomendarías hacer para escribir funciones simples __repr__() que se comporten bien con respecto a estas preguntas de codificación?

Respuesta

41

En Python2, __repr__ (y __str__) debe devolver un objeto de cadena, no un objeto unicode . En python3, la situación se invierte, y __repr____str__ debe devolver los objetos Unicode, no bytes (cadena de soltera) objetos:

class Foo(object): 
    def __repr__(self): 
     return u'\N{WHITE SMILING FACE}' 

class Bar(object): 
    def __repr__(self): 
     return u'\N{WHITE SMILING FACE}'.encode('utf8') 

repr(Bar()) 
# ☺ 
repr(Foo()) 
# UnicodeEncodeError: 'ascii' codec can't encode character u'\u263a' in position 0: ordinal not in range(128) 

en python2, usted realmente no tiene una opción. Debe elegir una codificación para el valor de retorno de __repr__.

Por cierto, ¿has leído el PrintFails wiki? Es posible que no responda directamente al sus otras preguntas, pero lo encontré útil para esclarecer por qué ocurren ciertos errores .


Al utilizar from __future__ import unicode_literals,

'<{}>'.format(repr(x).decode('utf-8'))).encode('utf-8') 

puede ser más simplemente escribir como

str('<{}>').format(repr(x)) 

asumiendo str codifica a utf-8 en su sistema.

Sin from __future__ import unicode_literals, la expresión se puede escribir como:

'<{}>'.format(repr(x)) 
+0

Sería bueno si la documentación menciona esto :) (http://docs.python.org/reference/datamodel.html#basic-customization no lo hace) ... En fin ... lo haría Dicen que el enfoque del punto 4 en la pregunta es engorroso pero necesario, ¿verdad? – EOL

+0

EOL: suponiendo que Python2, 'repr (x)' debe devolver una cadena codificada. Si estaba codificado con utf-8, entonces 'repr (x) .decode ('utf8'). Encode ('utf8')' no debería ser necesario. Si 'repr (x)' está codificado con alguna otra codificación, 'repr (x) .decode ('utf8')' fallará (con UnicodeDecodeError) o producirá resultados falsos, o tal vez se decodificará correctamente por casualidad afortunada. Entonces, AFAIK, 'repr (x) .decode ('utf8'). Encode ('utf8')' nunca debería ser necesario. ¿Puede dar un ejemplo? – unutbu

+2

@EOL, ** El valor de retorno debe ser un objeto de cadena. ** es cómo la página de manual de referencia que señala expresa la restricción de que el valor de retorno debe ser una instancia de 'str' (un objeto Unicode no sería" a " objeto de cadena "). 'repr' se espera _normally_ devuelva ascii solamente (cosa de' repr (uo) 'para todos los objetos Unicode, por ejemplo: incluso _hathat_ devuelve ascii solamente - creo que ningún built-in o tipo de biblioteca estándar se comporta de otra manera) pero estrictamente hablando esa no es una restricción de idioma, por lo que no es asunto del manual de referencia. ¡Los parches de documentación propuestos son siempre bienvenidos, por cierto! -) –

1

utilizo una función como la siguiente:

def stdout_encode(u, default='UTF8'): 
    if sys.stdout.encoding: 
     return u.encode(sys.stdout.encoding) 
    return u.encode(default) 

Entonces mis __repr__ funciones se ven así:

def __repr__(self): 
    return stdout_encode(u'<MyClass {0} {1}>'.format(self.abcd, self.efgh)) 
6

Creo que un decorador puede administrar __repr__ incomp atitudes de una manera sensata. Esto es lo que yo uso:

from __future__ import unicode_literals, print_function 
import sys 

def force_encoded_string_output(func): 

    if sys.version_info.major < 3: 

     def _func(*args, **kwargs): 
      return func(*args, **kwargs).encode(sys.stdout.encoding or 'utf-8') 

     return _func 

    else: 
     return func 


class MyDummyClass(object): 

    @force_encoded_string_output 
    def __repr__(self): 
     return 'My Dummy Class! \N{WHITE SMILING FACE}' 
+0

Bonito decorador; Lo modifiqué, sin embargo, para que '_func' no esté definido cuando no es necesario. Entonces, '__repr__' en Python 2 aparentemente puede devolver una cadena Unicode, de acuerdo con su código (¿tal vez por' unicode_literals'?). Esto choca con la respuesta sin respuesta ... Encuentro la documentación ambigua, en este (http://docs.python.org/2/reference/datamodel.html#object.__repr__, http://docs.python.org/2/reference /lexical_analysis.html#index-14). Me interesaría cualquier información de referencia sobre esto, solo para asegurarme de que no surjan problemas imprevistos al hacer que '__repr__' devuelva una cadena Unicode. – EOL

+0

@EOL * Entonces, '__repr__' en Python 2 aparentemente puede devolver una cadena Unicode (...) * ¿Por qué piensas eso? –

+0

Buena captura, mi mal. Eliminaré mi comentario anterior, ya que no es relevante. – EOL

Cuestiones relacionadas