Преобразование исключения в строку в Python 3
У кого-нибудь есть идея, почему этот код Python 3.2
try:
raise Exception('X')
except Exception as e:
print("Error {0}".format(str(e)))
работает без проблем (кроме кодировки Unicode в оболочке Windows:/),
но это
try:
raise Exception('X')
except Exception as e:
print("Error {0}".format(str(e, encoding = 'utf-8')))
throws TypeError: принуждение к str: нужны байты, bytearray или буферный объект, обнаружено исключение?
Как преобразовать ошибку в строку с пользовательской кодировкой?
Edit
Он также не работает, если в сообщении есть:\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 не может преобразовать исключение изнутри в байты?
Ответы
Ответ 1
В Python 3.x, str(e)
должен иметь возможность конвертировать любой Exception
в строку, даже если он содержит символы Unicode.
Поэтому, если ваше исключение фактически не возвращает закодированный байтовый массив UTF-8 в своем пользовательском методе __str__()
, str(e, 'utf-8')
не будет работать должным образом (он попытается интерпретировать 16-битную строку символов Unicode в ОЗУ как UTF-8 закодированный массив байтов...)
Я предполагаю, что ваша проблема не str()
, а print()
(т.е. шаг, который преобразует строку Юникода Python во что-то, что сбрасывается на консоль). См. Этот ответ для решений: Python, Unicode и консоль Windows
Ответ 2
Попробуйте это, он должен работать.
try:
raise Exception('X')
except Exception as e:
print("Error {0}".format(str(e.args[0])).encode("utf-8"))
Учитывая, что у вас есть только сообщение в вашем внутреннем кортеже.
Ответ 3
В Python3 string
не имеет такого атрибута, как кодирование. Он всегда unicode внутри. Для закодированных строк имеются байт-массивы:
s = "Error {0}".format(str(e)) # string
utf8str = s.encode("utf-8") # byte array, representing utf8-encoded text
Ответ 4
В Python 3 вы уже находитесь в "unicode space" и не нуждаетесь в кодировке. В зависимости от того, чего вы хотите достичь, вы должны немедленно выполнить преобразование, прежде чем делать что-то.
например. вы можете преобразовать все это в bytes()
, а скорее в направлении
bytes("Error {0}".format(str(e)), encoding='utf-8')
.
Ответ 5
Здесь есть версия-агностическое преобразование:
# 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)