Подтвердить что ты не робот

Python и Unicode: как все должно быть Unicode

Простите, если это длинный вопрос:

Я программировал в Python около шести месяцев. Самоучитель, начиная с учебника Python, а затем SO, а затем просто используя Google для прочего.

Вот грустная часть: никто не сказал мне, что все строки должны быть Unicode. Нет, я не врежу и не делаю это, но где это учить? И большинство примеров также я просто использую byte strings, а не Unicode strings., я просто просматривал и наткнулся на этот вопрос на qaru.site/info/233349/..., в котором говорится, что каждая строка в Python должна быть строка Unicode. Это в значительной степени заставило меня плакать!

Я читал, что каждая строка в Python 3.0 по умолчанию является Unicode, поэтому мои вопросы касаются 2.x:

  • Должен ли я сделать:

    print u'Some text' или просто print 'Text'?

  • Все должно быть Unicode, значит ли это, например, у меня есть tuple:

    t = ('First', 'Second'), it should be t = (u'First', u'Second')?

    Я читал, что могу сделать from __future__ import unicode_literals, и тогда каждая строка будет строкой Unicode, но я должен делать это и внутри контейнера?

  • При чтении/записи в файл я должен использовать модуль codecs. Правильно? Или я должен просто использовать стандартный способ или чтение/запись и encode или decode, где это необходимо?

  • Если я получаю строку от say raw_input(), должен ли я преобразовать ее в Unicode?

Каков общий подход к решению всех вышеперечисленных проблем в 2.x? Оператор from __future__ import unicode_literals?

Жаль, что я такой noob, но это меняет то, что я делаю в течение долгого времени, и поэтому я смущен.

4b9b3361

Ответ 1

Предложение "всегда использовать Юникод" в первую очередь облегчает переход на Python 3. Если в вашем коде имеется много строк, не связанных с Unicode, для его переноса потребуется больше работы.

Кроме того, вам не нужно принимать решение в каждом конкретном случае, следует ли хранить строку в виде Unicode или нет. Вам не нужно менять типы ваших строк и их синтаксис только потому, что вы изменили их содержимое.

Также легко использовать неправильный тип строки, приводящий к обычному коду, или код, который работает в Linux, но не в Windows, или в одном локали, но не в другом. Например, for c in "漢字" в локали UTF-8 будет перебирать каждый байт UTF-8 (все шесть из них), а не над каждым символом; зависит от того, что вы делаете с ними.

В принципе, ничто не должно ломаться, если вы используете строки Unicode, но все может сломаться, если вы используете обычные строки, если не хотите.

На практике, однако, больно использовать строки Unicode повсюду в Python 2. codecs.open не выбирает правильную локаль автоматически; это не удается:

codecs.open("blar.txt", "w").write(u"漢字")

Реальный ответ:

import locale, codecs
lang, encoding = locale.getdefaultlocale()
codecs.open("blar.txt", "w", encoding).write(u"漢字")

... который является громоздким, заставляя людей создавать вспомогательные функции только для открытия файлов. codecs.open следует использовать кодировку из locale автоматически, если она не указана; Недостатком Python для упрощения такой простой операции является одна из причин, по которым люди вообще не используют Unicode везде.

Наконец, обратите внимание, что строки Unicode в некоторых случаях еще более критичны в Windows. Например, если вы находитесь в западном регионе и у вас есть файл с именем "漢字", вы должны использовать строку Unicode для доступа к нему, например. os.stat(u"漢字"). Невозможно получить к нему доступ с помощью строки, отличной от Юникода; он просто не увидит файл.

Итак, в принципе, я бы сказал, что рекомендация строки Юникода разумна, но с предостережением, что я обычно даже не выполняю его сам.

Ответ 2

Нет, не каждая строка должна быть Unicode. Внутри вашего кода Python вы знаете, что строковые литералы должны быть Unicode или нет, поэтому нет смысла делать каждый строковый литерал в литерале Unicode.

Но есть случаи, когда вы должны использовать Unicode. Например, если у вас есть произвольный ввод текста, используйте Unicode для него. Вы рано или поздно найдете неамериканца, использующего его, и он хочет, чтобы он был нанят ås hé is üsed tö. И вы получите проблемы в этом случае, если только ваш вход и выход не используют ту же кодировку, о которой вы не можете быть уверены.

Короче говоря, нет, строки не должны быть Unicode. Текст должен быть. Но YMMV.

В частности:

  • Не нужно использовать Юникод здесь. Вы знаете, что эта строка ASCII или нет.

  • Зависит, если вам нужно объединить эти строки с Unicode или нет.

  • Оба способа работают. Но не кодируйте декодирование "при необходимости". Декодировать ASAP, кодировать как можно позже. Использование кодеков хорошо работает (или io, из Python 2.7).

  • Да.

Ответ 3

IMHO (мои простые правила):

  • Должен ли я выполнить: print u'Some text' or just print 'Text'?

  • Все должно быть Unicode, значит ли это, например, у меня есть кортеж: t = ('First', 'Second'), it should be t = (u'First', u'Second')?

Ну, я использую литералы Unicode только тогда, когда у меня есть char выше ASCII 128:

   print 'New York', u'São Paulo'
   t = ('New York', u'São Paulo')
  • При чтении/записи файла я должен использовать модуль кодеков. Правильно? Или я должен просто использовать стандартный способ или чтение/запись, а также кодировать или декодировать, где это необходимо?

Если вы ожидаете текст в Юникоде, используйте кодеки.

  • Если я получу строку из слова raw_input(), должен ли я преобразовать ее в Unicode?

Только если вы ожидаете, что текст в Юникоде может быть перенесен в другую систему с различной кодировкой по умолчанию (включая базы данных).

EDITED (о смешении unicode и байтовых строк):

>>> print 'New York', 'to', u'São Paulo'
New York to São Paulo
>>> print 'New York' + ' to ' + u'São Paulo'
New York to São Paulo
>>> print "Côte d'Azur" + ' to ' + u'São Paulo'
Traceback (most recent call last):
  File "<interactive input>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 1: 
     ordinal not in range(128)
>>> print "Côte d'Azur".decode('utf-8') + ' to ' + u'São Paulo'
Côte d'Azur to São Paulo

Итак, если вы смешаете строку байтов, содержащую utf-8 (или другую не ascii char) с текстом unicode без явного преобразования, у вас возникнут проблемы, поскольку по умолчанию предполагается ascii. Другой способ, как кажется, безопасен. Если вы следуете правилу написания каждой строки, содержащей non-ascii, как литерал в Юникоде, вы должны быть в порядке.

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Я живу в Бразилии, где люди говорят по-португальски, язык с множеством символов не-ascii. Моя кодировка по умолчанию всегда установлена ​​на "utf-8". Ваш пробег может отличаться в системах на английском языке/ascii.

Ответ 4

Я просто добавляю свое личное мнение здесь. Не так долго и подробно на других ответах, но, возможно, он тоже может помочь.

print u'Some text' или просто print 'Text'?

Идентификатор действительно предпочитает первый. Если вы знаете, что у вас есть только строки Unicode, у вас есть еще один инвариант. Различные другие языки (C, С++, Perl, PHP, Ruby, Lua,...) иногда сталкиваются с болезненными проблемами из-за отсутствия разделения между последовательностями блоков кода и целыми последовательностями. Я нахожу подход строгого различия между ними, который существует в .NET, Java, Python и т.д. Довольно чистым.

Все должно быть Unicode, значит ли это, например, у меня есть кортеж:

t = ('First', 'Second'), это должно быть t = (u'First', u'Second')?

Да.

Я читал, что могу сделать from __future__ import unicode_literals, и тогда каждая строка будет строкой Unicode, но я должен делать это и внутри контейнера?

Да. Будущие утверждения относятся только к файлу, в котором они используются, поэтому вы можете использовать их без вмешательства в другие модули. Я вообще импортирую все фьючерсы в Python 2.x, чтобы упростить переход на 3.x.

При чтении/записи в файл я должен использовать модуль codecs. Правильно? Или я должен просто использовать стандартный способ или чтение/запись, а также кодировать или декодировать, где это необходимо?

Вы должны использовать модуль codecs, потому что это делает невозможным (или, по крайней мере, очень тяжелое) случайное создание по-разному кодированных представлений в один файл. Это также способ, которым работает Python 3.x, когда вы открываете файл в текстовом режиме.

Если я получаю строку от say raw_input(), должен ли я преобразовать ее в Unicode?

Ид сказать "да" тоже: в большинстве случаев проще иметь дело только с одной кодировкой, поэтому я рекомендую как можно раньше конвертировать в строки Unicode Python.

Каков общий подход к решению всех вышеперечисленных проблем в 2.x? Оператор from __future__ import unicode_literals?

Я не знаю, что такое общий подход, но я все время использую этот оператор. Я столкнулся с очень небольшим количеством проблем с этим подходом, и большинство из них связаны с ошибками во внешних библиотеках, т.е. NumPy иногда требует байтовых строк, не документируя это.

Ответ 5

Тот факт, что вы пишете код Python в течение 6 месяцев, прежде чем встретить что-нибудь о Unicode, означает, что Python 2.x ASCII по умолчанию для строк не вызывал у вас никаких проблем. Разумеется, для новичка, чтобы попытаться понять идею Unicode/кодовых пунктов/кодирования сама по себе, трудно решить; поэтому большинство учебников естественно обходят его, пока вы не получите больше оснований в фундаментальных принципах. Поэтому в книге, подобной "Dive Into Python", Unicode упоминается в последующих главах.

Если вам нужно поддерживать Unicode в своем приложении, я предлагаю просмотреть Kumar McMillan PyCon 2008 в Unicode для получения списка лучших практик. Он должен ответить на оставшиеся вопросы.

Ответ 6

1/2) Лично я никогда не слышал о "всегда использовании юникода". Это кажется мне довольно глупым. Думаю, я понимаю, если вы планируете поддерживать другие языки, которые нуждаются в поддержке юникода. Но кроме этого я бы этого не сделал, это похоже на боль, чем это стоит.

3) Я бы просто прочитал/записал стандартный путь и закодировал, когда это необходимо.