Самая большая проблема, которая не может быть адекватно устранена изменениями на микроуровне и 2to3, - это изменение тип строки по умолчанию от байтов до Unicode.
Если вашему коду нужно что-либо делать с кодировками и байтовыми вводами-выводами, понадобится куча ручных усилий для правильной конвертации, так что вещи, которые должны быть байтами, остаются байтами и соответствующим образом декодируются справа сцена. Вы обнаружите, что некоторые строковые методы (в частности, format()
) и вызовы библиотек требуют строк Unicode, поэтому вам могут потребоваться дополнительные циклы декодирования/кодирования, чтобы использовать строки как Unicode, даже если они действительно просто байты.
Этому не способствует тот факт, что некоторые из стандартных модулей библиотеки Python были грубо преобразованы с использованием 2to3 без должного внимания к проблемам с байтами/юникодом/кодированием и поэтому сами ошибаются в отношении типа строки. Некоторые из них вырвались, но, по крайней мере, с 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, и большинство кодировок не могут отображать все возможные символы к байтам. Это источник всех тех проблем, при которых вы загружаете файл из одного языкового стандарта в приложение 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 будет использоваться для их взлома во многих приложениях, поэтому для вас это, скорее всего, не критично.
В «широких строках» строки Юникода выполнены из блоков «кодовой точки» реального символа, поэтому даже расширенные символы вне BMP можно обрабатывать последовательно и легко. Цена за это - эффективность: каждый струнный блок занимает четыре байта памяти в памяти.
Когда речь заходит о байтовых и юникодовых строках, какая разница? Просто, что в байтовых строках используется байт на символ, а в unicode - два байта? –
"" "UTF-8 ... никакая другая кодировка не должна использоваться в современном приложении" "", если ваше правительство не поручает что-то еще, например. 'gb18030' :-) –
Это было * отлично * объяснение разницы между строками байтов и Unicode. Я был более или менее знаком с ASCII v. Unicode, но (очевидно) я не был знаком с тем, как Python (esp 3.x) справлялся с ними. Хотелось бы, чтобы я мог проголосовать более одного раза;) –