2010-08-06 6 views
11

Как мы все знаем к настоящему времени (надеюсь), Python 3 медленно начинает заменять Python 2.x. Конечно, это будет много MANY лет, прежде чем большая часть существующего кода, наконец, портирована, но есть вещи, которые мы можем сделать прямо сейчас в нашем коде версии 2.x, чтобы сделать коммутатор проще.Подготовка к конвертации из Python 2.x в 3.x

Очевидно, что взглянуть на what's new в 3.x будет полезно, но что мы можем сделать прямо сейчас, чтобы сделать предстоящее преобразование более безболезненным (а также упростить вывод обновлений для параллельных версий, если это необходимо)? Я специально задумываюсь о строках, с которых мы можем начать наши скрипты, что сделает более ранние версии Python более похожими на 3.x, хотя другие привычки также приветствуются.

Самый очевидный код, чтобы добавить в начало сценария, который я могу думать:

from __future__ import division 
from __future__ import print_function 
try: 
    range = xrange 
except NameError: 
    pass 

Самая очевидная привычка, что я могу думать о том, "{0} {1}!".format("Hello", "World") для строки форматирования.

Любые другие линии и хорошие привычки?

ответ

12

Самая большая проблема, которая не может быть адекватно устранена изменениями на микроуровне и 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 можно обрабатывать последовательно и легко. Цена за это - эффективность: каждый струнный блок занимает четыре байта памяти в памяти.

+0

Когда речь заходит о байтовых и юникодовых строках, какая разница? Просто, что в байтовых строках используется байт на символ, а в unicode - два байта? –

+0

"" "UTF-8 ... никакая другая кодировка не должна использоваться в современном приложении" "", если ваше правительство не поручает что-то еще, например. 'gb18030' :-) –

+0

Это было * отлично * объяснение разницы между строками байтов и Unicode. Я был более или менее знаком с ASCII v. Unicode, но (очевидно) я не был знаком с тем, как Python (esp 3.x) справлялся с ними. Хотелось бы, чтобы я мог проголосовать более одного раза;) –

5

Я пытаюсь привыкнуть к таким вещам, как var1//var2 всякий раз, когда я на самом деле хочу целое деление (а не поплавок). Не большой шаг к Python 3, но по крайней мере мне не придется возвращаться и проверять все мои подразделения :)

Смежные вопросы