Я смотрел на этот вопрос и начал задаваться вопросом, что делает print
на самом деле сделайте.
Я никогда не узнавал, как использовать string.decode()
и string.encode()
для вывода строки unicode в Python интерактивная оболочка в том же формате как, печать делает. Независимо от того, что я делаю, я добираюсь также
Это - Python 2.x, но я уже пытаюсь исправить свои пути и на самом деле звонить print()
:)
Пример:
>>> import sys
>>> a = '\xAA\xBB\xCC'
>>> print(a)
ª»Ì
>>> a.encode(sys.stdout.encoding)
Traceback (most recent call last):
File "", line 1, in ?
UnicodeDecodeError: 'ascii' codec can't decode byte 0xaa in position 0: ordinal not in range(128)
>>> a.decode(sys.stdout.encoding)
u'\xaa\xbb\xcc'
Править:
Почему я спрашиваю это? Я являюсь больным и усталым от encode()
ошибки и реализованный это с тех пор print
может сделать это (по крайней мере, в интерактивной оболочке). Я знаю, что ДОЛЖЕН ЯВЛЯЕТСЯ СПОСОБОМ волшебно сделать кодирование ПРАВИЛЬНО путем рытья информации что, кодируя для использования от где-нибудь...
ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ: я запускаю Python 2.4.3 (#1, 3 сентября 2009, 15:37:12) [GCC 4.1.2 20080704 (Red Hat 4.1.2-46)] на linux2
>>> sys.stdin.encoding
'ISO-8859-1'
>>> sys.stdout.encoding
'ISO-8859-1'
Однако результатами является то же с Python 2.6.2 (r262:71600, 8 сентября 2009, 13:06:43) на том же поле Linux.
EDIT: (Основные изменения между этим редактированием и предыдущим... Примечание: Я использую Python 2.6.4 на коробке Ubuntu.)
Во-первых, в моей первой попытке ответить, я предоставил некоторую общую информацию о печати
и str
, которые я собираюсь оставить ниже, в пользу любого, у кого есть более простые вопросы с печати
и направляя на этот вопрос. Что касается новой попытки решить проблему, с которой столкнулась ОП... В принципе, я склонен сказать, что здесь нет серебряной пули, и если печатает
каким-то образом умудряется придать смысл странному струнному буквальному, то это не воспроизводимое поведение. К такому выводу меня приводит следующее забавное взаимодействие с Python в окне моего терминала:
>>> print '\xaa\xbb\xcc'
��
Пытались ли вы ввести ª "М прямо из терминала? В терминале Linux, использующем в качестве кодировки utf-8, это на самом деле считывается как шесть байт, которые затем можно сделать похожими на три символа юникода с помощью метода decode
:
>>> 'ª»Ì'
'\xc2\xaa\xc2\xbb\xc3\x8c'
>>> 'ª»Ì'.decode(sys.stdin.encoding)
u'\xaa\xbb\xcc'
Итак, литерал '\xaa\xbb\xcc'
имеет смысл только в том случае, если вы декодируете его как литерал latin-1 (ну, на самом деле, вы могли бы использовать другую кодировку, которая бы согласовывалась с латинским-1 на соответствующих символах). Что касается распечатки
"просто работает" в вашем случае, то это определенно не для меня -- как уже упоминалось выше.
Это объясняется тем, что когда вы используете строковый литерал без префикса с u
-- т.е. "asdf"
, а не u "asdf"
-- результирующая строка будет использовать некоторую некодированную кодировку. Нет; на самом деле, сам строковый объект будет в кодировке - не в кодировке, и вам придется относиться к нему так, как будто он был закодирован в кодировке x, для правильного значения x. Эта основная идея приводит меня к следующему:
a = '\xAA\xBB\xCC'
a.decode('latin1')
# result: u'\xAA\xBB\xCC'
print(a.decode('latin1'))
# output: ª»Ì
Обратите внимание на отсутствие ошибок декодирования и правильный вывод (который, как я ожидаю, останется правильным на любом другом ящике). Видимо, ваш строковый литерал может быть понятен Python, но не без некоторой помощи.
Помогает ли это? (По крайней мере, в понимании того, как все работает, если не в облегчении работы с кодировками...)
Теперь для некоторых забавных битов с каким-то поясняющим значением (надеюсь)! Для меня это отлично работает:
sys.stdout.write("\xAA\xBB\xCC".decode('latin1').encode(sys.stdout.encoding))
Пропуск либо декодирования, либо части кодирования приводит к исключению, связанному с юникодом. Теоретически, это имеет смысл, так как первый дешифровочный код необходим, чтобы решить, какие символы в данной строке есть (единственное, что очевидно на первый взгляд, это то, что байты есть -- идея Python 3 иметь (уникодовые) строки для символов и байты для, ну, байтов, внезапно кажется очень разумной), в то время как кодирование необходимо для того, чтобы вывод уважал кодировку выходного потока. Теперь это
sys.stdout.write("ąöî\n".decode(sys.stdin.encoding).encode(sys.stdout.encoding))
также работает, как и ожидалось, но символы на самом деле идут с клавиатуры и поэтому на самом деле закодированы в кодировке stdin... Также
ord('ą'.decode('utf-8').encode('latin2'))
возвращает правильную 177 (моя входная кодировка utf-8), но '\xc4\x85'.encode('latin2') не имеет смысла для Python, так как он понятия не имеет, как понять '\xc4\x85' и цифры, что пробовать 'ascii' код - это лучшее, что он может сделать.
Первоначальный ответ:
Соответствующий бит Python docs (для версии 2.6.4) говорит, что print(obj)
предназначен для распечатки строки, заданной str(obj)
. Я полагаю, что вы могли бы затем обернуть это в обращение к unicode
(как в unicode(str(obj))
), чтобы получить строку из unicode -- или вы могли бы просто использовать Python 3 и обменять эту конкретную неприятность на пару разных. ;-)
Кстати, это показывает, что вы можете манипулировать результатом распечатки
объекта так же, как вы можете манипулировать результатом вызова str
на объекте, т.е. путем манипулирования методом __str__
. Пример:
class Foo(object):
def __str__(self):
return "I'm a Foo!"
print Foo()
Что касается фактической реализации print
, то я ожидаю, что это будет совсем не полезно, но если вы действительно захотите узнать, что происходит.... Это находится в файле Python/bltinmodule.c
в исходниках Python (я смотрю на версию 2.6.4). Ищите строку, начинающуюся с builtin_print
. На самом деле это совершенно просто, никакой магии там не происходит. :-)
Надеюсь, это ответ на ваш вопрос... Но если у вас есть более загадочная проблема, которую я полностью пропустил, сделайте комментарий, я сделаю вторую попытку. Также, я предполагаю, что мы имеем дело с Python 2.x; в противном случае, я думаю, что у меня не было бы полезного комментария.
print()
использует sys.stdout.encoding
, чтобы определить, что выходная консоль может понять, а затем использует эту кодировку в вызове str.encode()
.
[EDIT] Если вы посмотрите на источник , он получает sys.stdout
и затем звонит:
PyFile_WriteObject(PyTuple_GetItem(args, i), file,
Py_PRINT_RAW);
Я думаю, что магия находится в Py_PRINT_RAW
, но источник просто говорит:
if (flags & Py_PRINT_RAW) {
value = PyObject_Str(v);
}
Так что никакой магии здесь нет. Цикл по аргументам с sys.stdout.write(str(item))
должен выполнить этот трюк.
import sys
source_file_encoding = 'latin-1' # if there is no -*- coding: ... -*- line
a = '\xaa\xbb\xcc' # raw bytes that represent string in source_file_encoding
# print bytes, my terminal tries to interpret it as 'utf-8'
sys.stdout.write(a+'\n')
# -> ��
ua = a.decode(source_file_encoding)
sys.stdout.write(ua.encode(sys.stdout.encoding)+'\n')
# -> ª»Ì
>>> import sys
>>> a = '\xAA\xBB\xCC'
>>> print(a)
ª»Ì
]
[] Все, что [] распечатка [
] делает здесь, это записывает необработанные [] байты [] в [] sys.stdout [
]. Строка []a[
] представляет собой строку из байтов, а не символов Юникода.[
] [] [] Почему я спрашиваю об этом? Я устал от ошибок encode() и понял, что так как print может это делать (по крайней мере, в интерактивной оболочке). Я знаю, что ДОЛЖЕН МОЖНО ПОЛУЧАТЬ магически сделать кодировку ПРЕДЛОЖИТЕЛЬНО, выкопав откуда-то информацию о том, какую кодировку использовать...[
]. [
] Увы, нет, [] печать [
] здесь совсем ничего не волшебного. Вы даете ему несколько байтов, а он сбрасывает байты в stdout. [
] Чтобы правильно использовать [].encode()[
] и [].decode()[
], вы должны понимать разницу между байтами и символами, и я боюсь, что вам все-таки придется вычислить правильную кодировку, чтобы использовать ее.[