Преобразование исключения в строку в Python 3 - PullRequest
42 голосов
/ 16 августа 2011

у кого-нибудь есть идея, почему этот код Python 3.2

try:    
    raise Exception('X')
except Exception as e:
    print("Error {0}".format(str(e)))

работает без проблем (кроме кодировки Unicode в Windows Shell: /), но это

try:    
    raise Exception('X')
except Exception as e:
    print("Error {0}".format(str(e, encoding = 'utf-8')))

throws TypeError: приведение к str: нужны байты, байтовый массив или буфероподобный объект, исключение найдено ?

Как преобразовать ошибку в строку с пользовательской кодировкой?

Редактировать

Не работает, если в сообщении есть \ u2019:

try:    
    raise Exception(msg)
except Exception as e:
    b = bytes(str(e), encoding = 'utf-8')
    print("Error {0}".format(str(b, encoding = 'utf-8')))

Но почему str () не может преобразовать внутреннее исключение в байты?

Ответы [ 5 ]

42 голосов
/ 16 августа 2011

В Python 3.x str(e) должен иметь возможность преобразовывать любые Exception в строку, даже если она содержит символы Unicode.

Так что, если ваше исключение фактически не возвращает байт в кодировке UTF-8массив в его пользовательском методе __str__(), str(e, 'utf-8') не будет работать должным образом (он попытается интерпретировать 16-битную символьную строку Юникода в ОЗУ как байтовый массив в кодировке UTF-8 ...)

Мои предположенияв том, что ваша проблема не в str(), а в print() (то есть шаг, который преобразует строку Python Unicode во что-то, что выводится на вашу консоль).См. Этот ответ для решений: Python, Unicode и консоль Windows

10 голосов
/ 16 августа 2011

Попробуйте, это должно работать.

try:    
    raise Exception('X')
except Exception as e:
    print("Error {0}".format(str(e.args[0])).encode("utf-8"))

Учитывая, что в вашем внутреннем кортеже есть только сообщение.

4 голосов
/ 16 августа 2011

В Python3, string не имеет такого атрибута, как кодировка.Это всегда внутри Юникода.Для закодированных строк существуют байтовые массивы:

s = "Error {0}".format(str(e)) # string
utf8str = s.encode("utf-8") # byte array, representing utf8-encoded text
3 голосов
/ 16 августа 2011

В Python 3 вы уже находитесь в «пространстве Юникода» и не нуждаетесь в кодировании.В зависимости от того, чего вы хотите достичь, вы должны выполнить преобразование непосредственно перед тем, как делать что-либо.

Например, вы можете преобразовать все это в bytes(), а скорее в направлении

bytes("Error {0}".format(str(e)), encoding='utf-8')

.

0 голосов
/ 09 февраля 2017

Здесь есть не зависящее от версии преобразование:

# from the `six` library
import sys
PY2 = sys.version_info[0] == 2
if PY2:
    text_type = unicode
    binary_type = str
else:
    text_type = str
    binary_type = bytes

def exc2str(e):
    if e.args and isinstance(e.args[0], binary_type):
        return e.args[0].decode('utf-8')
    return text_type(e)

и тесты для него:

def test_exc2str():
    a = u"\u0856"
    try:
        raise ValueError(a)
    except ValueError as e:
        assert exc2str(e) == a
        assert isinstance(exc2str(e), text_type)
    try:
        raise ValueError(a.encode('utf-8'))
    except ValueError as e:
        assert exc2str(e) == a
        assert isinstance(exc2str(e), text_type)
    try:
        raise ValueError()
    except ValueError as e:
        assert exc2str(e) == ''
        assert isinstance(exc2str(e), text_type)
...