Лучший тип вывода и методы кодирования для функций __repr __()?

В последнее время у меня были проблемы с __repr__(), format() и кодировками. Если вывод __repr__() должен быть закодирован или быть строкой в ​​формате Юникод? Есть ли лучшая кодировка для результата __repr__() в Python? То, что я хочу выводить, имеет символы, отличные от ASCII.

Я использую Python 2.x и хочу написать код, который можно легко адаптировать к Python 3. Таким образом, программа использует

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

Вот некоторые дополнительные проблемы, которые меня беспокоят, и я ищу решение, которое их решает:

  • Должна работать печать на терминал UTF-8 (у меня sys.stdout.encoding установлен на UTF-8, но было бы лучше, если бы и другие дела работали тоже).
  • Работа с выходом в файл (закодирована в UTF-8) должна работать (в этом случае sys.stdout.encoding есть None).
  • Мой код для многих функций __repr__() в настоящее время имеет много return ….encode('utf-8'), и это тяжело. Есть ли что-нибудь надежное и легкое?
  • В некоторых случаях у меня даже есть уродливые звери, такие как return ('<{}>'.format(repr(x).decode('utf-8'))).encode('utf-8'), то есть представление объектов декодируется, помещается в строку форматирования и затем повторно кодируется. Я бы хотел избежать таких запутанных преобразований.

Что вы посоветуете, чтобы написать простые функции __repr__(), которые хорошо относятся к этим вопросам кодирования?

Ответ 1

В Python2, __repr____str__) должен возвращать строковый объект, а не unicode. В Python3 ситуация меняется на обратную, __repr__ и __str__ должен возвращать объекты unicode, а не байтовые (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)

В Python2 у вас действительно нет выбора. Вы должны выбрать кодировку для возвращаемое значение __repr__.

Кстати, прочитали ли вы PrintFails wiki? Он может не отвечать напрямую ваши другие вопросы, но я нашел полезным в освещении, почему некоторые возникают ошибки.


При использовании from __future__ import unicode_literals,

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

можно просто записать в виде

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

Предполагая, что str кодируется в utf-8 в вашей системе.

Без from __future__ import unicode_literals выражение может быть записано как:

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

Ответ 2

Я думаю, что декоратор может разумно управлять несовместимостью __repr__. Вот что я использую:

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

Ответ 3

Я использую следующую функцию:

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

Затем мои функции __repr__ выглядят так:

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