Melhor tipo de saída e práticas de codificação para funções __repr __ ()?
Pergunta
Ultimamente, tive muitos problemas com __repr__()
, format()
, e codificações. Deve a saída de __repr__()
ser codificado ou ser uma string unicode? Existe uma melhor codificação para o resultado de __repr__()
em Python? O que eu quero que a saída possui caracteres não-ASCII.
Eu uso o Python 2.x e quero escrever um código que possa ser facilmente adaptado ao Python 3. O programa assim usa
# -*- coding: utf-8 -*-
from __future__ import unicode_literals, print_function # The 'Hello' literal represents a Unicode object
Aqui estão alguns problemas adicionais que estão me incomodando, e estou procurando uma solução que os resolve:
- Imprimir para um terminal UTF-8 deve funcionar (eu tenho
sys.stdout.encoding
definido comoUTF-8
, mas seria melhor se outros casos também funcionassem). - Tanque a saída para um arquivo (codificado no UTF-8) deve funcionar (neste caso,
sys.stdout.encoding
éNone
). - Meu código para muitos
__repr__()
As funções atualmente têm muitasreturn ….encode('utf-8')
, e isso é pesado. Existe algo robusto e mais leve? - Em alguns casos, eu até tenho bestas feias como
return ('<{}>'.format(repr(x).decode('utf-8'))).encode('utf-8')
, ou seja, a representação dos objetos é decodificada, colocada em uma string de formatação e depois recodificada. Eu gostaria de evitar transformações tão complicadas.
O que você recomendaria fazer para escrever simples __repr__()
Funções que se comportam bem com relação a essas perguntas de codificação?
Solução
Em python2, __repr__
(e __str__
) deve retornar um objeto String, não um objeto Unicode. No python3, a situação é revertida, __repr__
e __str__
Deve retornar objetos unicode, não byte (string née) 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)
No Python2, você realmente não tem escolha. Você tem que escolher uma codificação para o valor de retorno de __repr__
.
A propósito, você leu o PrintFails Wiki? Pode não responder diretamente às suas outras perguntas, mas achei útil para esclarecer por que certos erros ocorrem.
Ao usar from __future__ import unicode_literals
,
'<{}>'.format(repr(x).decode('utf-8'))).encode('utf-8')
pode ser mais simplesmente escrito como
str('<{}>').format(repr(x))
assumindo str
codifica para utf-8
no seu sistema.
Sem from __future__ import unicode_literals
, a expressão pode ser escrita como:
'<{}>'.format(repr(x))
Outras dicas
Eu acho que um decorador pode gerenciar __repr__
incompatibilidades de maneira sã. Aqui está o que eu 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}'
Eu uso uma função como a seguinte:
def stdout_encode(u, default='UTF8'):
if sys.stdout.encoding:
return u.encode(sys.stdout.encoding)
return u.encode(default)
Então meu __repr__
As funções são assim:
def __repr__(self):
return stdout_encode(u'<MyClass {0} {1}>'.format(self.abcd, self.efgh))