ti-enxame.com

Melhores práticas de codificação e tipo de saída para funções __repr __ ()?

Ultimamente, tenho tido muitos problemas com __repr__(), format() e codificações. A saída de __repr__() deve ser codificada ou ser uma string unicode? Existe a melhor codificação para o resultado de __repr__() em Python? O que eu quero gerar possui caracteres não ASCII.

Eu uso Python 2.xe quero escrever 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 me incomodam e estou procurando uma solução que os resolva:

  1. A impressão em um terminal UTF-8 deve funcionar (eu tenho sys.stdout.encoding Definido como UTF-8, Mas seria melhor que outros casos funcionassem também).
  2. A canalização da saída para um arquivo (codificado em UTF-8) deve funcionar (nesse caso, sys.stdout.encoding É None).
  3. Meu código para muitas funções __repr__() atualmente tem muitos return ….encode('utf-8'), e isso é pesado. Existe algo robusto e mais leve?
  4. Em alguns casos, tenho até bestas feias como return ('<{}>'.format(repr(x).decode('utf-8'))).encode('utf-8'), ou seja, a representação dos objetos é decodificada, colocada em uma sequência de formatação e depois recodificada. Eu gostaria de evitar essas transformações complicadas.

O que você recomendaria fazer para escrever funções simples __repr__() que se comportam bem com relação a essas perguntas de codificação?

66
Eric O Lebigot

No Python2, __repr__ (e __str__) deve retornar um objeto string, não um objeto unicode. No Python3, a situação é invertida, __repr__ e __str__ deve retornar objetos unicode, não objetos byte (née string):

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ê precisa escolher uma codificação para o valor de retorno __repr__.

A propósito, você leu o PrintFails wiki ? Pode não responder diretamente às suas outras perguntas, mas achei útil 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 que str codifica para utf-8 no seu sistema.

Sem from __future__ import unicode_literals, a expressão pode ser escrita como:

'<{}>'.format(repr(x))
41
unutbu

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}'
6
Titon

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__ funções são assim:

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