Ответ 1
Самая большая проблема, которая не может быть адекватно устранена изменениями на микроуровне и 2to3, - это изменение типа строки по умолчанию от байтов до Unicode.
Если вашему коду нужно что-то делать с кодировками и байтовыми вводами-выводами, потребуется скопировать ручное усилие для правильной конвертации, так что вещи, которые должны быть байтами, остаются байтами и соответствующим образом декодируются на нужной стадии, Вы обнаружите, что некоторые строковые методы (в частности, format()
) и вызовы библиотеки требуют строк Unicode, поэтому вам могут потребоваться дополнительные циклы декодирования/кодирования, чтобы использовать строки как Unicode, даже если они действительно просто байты.
Этому не помогает тот факт, что некоторые из стандартных модулей библиотеки Python были грубо преобразованы с использованием 2to3 без должного внимания к проблемам с байтами /unicode/encoding, поэтому сами ошибаются в том, какой тип строки подходит. Некоторые из них вырваны, но, по крайней мере, с Python 3.0 до 3.2 вы столкнетесь с запутанным и потенциально ошибочным поведением из пакетов, таких как urllib, email и wsgiref, которые должны знать о байтовых кодировках.
Вы можете улучшить проблему, соблюдая осторожность при написании строкового литерала. Используйте строки u''
для чего-либо, что по сути основано на символьных строках, b''
для чего-либо, что действительно байтов, и ''
для типа строки по умолчанию, где это не имеет значения, или вам нужно соответствовать требованиям использования строки вызова библиотеки.
К сожалению, синтаксис b''
был введен только в Python 2.6, поэтому это сокращает пользователей более ранних версий.
ета:
какая разница?
О, мой. Ну...
Байт содержит значение в диапазоне 0-255 и может представлять нагрузку двоичных данных (например, содержимое изображения) или какой-либо текст, и в этом случае должен быть выбран стандарт, как отображать набор символов в эти байты. Большинство этих стандартов кодирования сопоставляют нормальный набор символов ASCII в байтах 0-127 одинаково, поэтому в целом безопасно использовать байтовые строки для обработки текста только ASCII в Python 2.
Если вы хотите использовать любой из символов вне ASCII-набора в байтовой строке, у вас проблемы, потому что каждая кодировка отображает другой набор символов в остальные байтовые значения 128-255, и большинство кодировок могут " t отображает все возможные символы в байты. Это источник всех тех проблем, при которых вы загружаете файл из одного языкового стандарта в приложение Windows в другой языковой стандарт, и все буквы с акцентом или не латинскими буквами меняются на неправильные, что делает нечитаемым беспорядок. (aka 'mojibake.)
Существуют также "многобайтовые кодировки", которые позволяют помещать больше символов в доступное пространство, используя более одного байта для хранения каждого символа. Они были введены для восточноазиатских локаций, так как так много китайских иероглифов. Но есть также UTF-8, более современная многобайтовая кодировка, которая может вместить каждый символ.
Если вы работаете с байтовыми строками в многобайтовой кодировке, и сегодня вы, вероятно, будете, потому что UTF-8 очень широко используется; на самом деле, никакая другая кодировка не должна использоваться в современном приложении - тогда у вас есть еще больше проблем, чем просто отслеживать, с какой кодировкой вы играете. len()
будет сообщать вам длину в байтах, а не длину в символах, и если вы начнете индексирование и изменение байтов, вы, скорее всего, сломаете многобайтовую последовательность пополам, создавая недопустимую последовательность и обычно путайте все.
По этой причине Python 1.6 и более поздние версии имеют собственные строки Unicode (пишется u'something'
), где каждая единица в строке является символом, а не байтом. Вы можете len()
их, нарежьте их, замените их, повторно выведите их, и они всегда будут вести себя надлежащим образом. Для задач обработки текста они, несомненно, лучше, поэтому Python 3 делает их строковым типом по умолчанию (без размещения u
до ''
).
Ловушка заключается в том, что многие существующие интерфейсы, такие как имена файлов в ОС, отличных от Windows, или HTTP или SMTP, в основном основаны на байтах с отдельным способом указания кодировки. Поэтому, когда вы имеете дело с компонентами, которые нуждаются в байтах, вам нужно правильно закодировать строки юникода в байтах, а в Python 3 вам придется делать это явно в некоторых местах, где раньше вам не нужно.
Это внутренняя деталь реализации, в которой строки Unicode берут два байта памяти на единицу внутри. Вы никогда не увидите это хранилище; вы не должны думать об этом с точки зрения байтов. Единицы, над которыми вы работаете, являются концептуально символами, независимо от того, как Python хочет их представлять в памяти.
... в сторону:
Это не совсем так. "Узкие сборки Python, такие как сборка Windows, каждая единица строки Unicode не является технически символом, а модулем UTF-16". Для символов в базовой многоязычной плоскости от 0x0000-0xFFFF вы не заметите какой-либо разницы, но если вы используете символы извне этого 16-битного диапазона, то в "астральных плоскостях" вы обнаружите, что они принимают два единиц вместо одного, и, опять же, вы рискуете разбить персонажа, когда вы нарезаете их.
Это очень плохо, и произошло потому, что Windows (и другие, такие как Java) установили UTF-16 как механизм хранения в памяти до того, как Unicode вырос за пределы 65 000 символов. Тем не менее, использование этих расширенных символов по-прежнему довольно редко, и любой пользователь Windows будет использовать их во многих приложениях, поэтому он, вероятно, не критичен для вас.
В строгих строках Unicode строятся единицы кода реального символа, поэтому даже расширенные символы вне BMP можно обрабатывать последовательно и легко. Цена за это - эффективность: каждый струнный блок занимает 4 байта памяти в памяти.