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:

  1. Imprimir para um terminal UTF-8 deve funcionar (eu tenho sys.stdout.encoding definido como UTF-8, mas seria melhor se outros casos também funcionassem).
  2. Tanque a saída para um arquivo (codificado no UTF-8) deve funcionar (neste caso, sys.stdout.encoding é None).
  3. Meu código para muitos __repr__() As funções atualmente têm muitas return ….encode('utf-8'), e isso é pesado. Existe algo robusto e mais leve?
  4. 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?

Foi útil?

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))
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top