Навіщо оголошувати unicode рядком у python?


122

Я все ще вивчаю пітон, і я маю сумніви:

У python 2.6.x я зазвичай декларую кодування у заголовку файлу таким чином (як у PEP 0263 )

# -*- coding: utf-8 -*-

Після цього мої рядки записуються як завжди:

a = "A normal string without declared Unicode"

Але щоразу, коли я бачу код проекту python, кодування не оголошується в заголовку. Замість цього він оголошується в кожному рядку, як це:

a = u"A string with declared Unicode"

Яка різниця? Яка мета цього? Я знаю, що Python 2.6.x встановлює кодування ASCII за замовчуванням, але це може бути замінено декларацією заголовка, тож який сенс у оголошенні рядка?

Додаток: Здається, я змішав кодування файлів із строковим кодуванням. Дякую за пояснення :)


6
# coding: utf8досить хороший, не потрібно-*-
медузи

1
@jellyfish Я припускаю, що ти мав намір набрати текст # coding: utf-8.
Самуель Хармер

Повинно бути #coding=utf-8. python.org/dev/peps/pep-0263
Шень

Відповіді:


167

Як це говорили інші, це дві різні речі.

Коли ви вказуєте# -*- coding: utf-8 -*- , ви повідомляєте Python, який файл, який ви зберегли, є utf-8. Типовим для Python 2 є ASCII (для Python 3 - це utf-8). Це просто впливає на те, як перекладач читає символи у файлі.

Взагалі, це, мабуть, не найкраща ідея вставляти у свій файл високі символи Unicode незалежно від кодування; ви можете використовувати рядок унікод-рядок, які працюють у будь-якому кодуванні.


Коли ви оголошуєте рядок з uфронтом , наприклад u'This is a string', він повідомляє компілятору Python, що рядок є Unicode, а не байтами. З цим перекладач в основному справляється прозоро; найочевидніша відмінність полягає в тому, що тепер ви можете вставляти символи unicode у рядок (тобто u'\u2665'це тепер законно). Ви можете використовувати, from __future__ import unicode_literalsщоб зробити його за замовчуванням.

Це стосується лише Python 2; у Python 3 за замовчуванням є Unicode, і вам потрібно вказати a bспереду (наприклад b'These are bytes', оголосити послідовність байтів).


Дякую за пояснення! Я встановлю це як прийняте, оскільки це найповніше :)
Оскар Карбаллал

2
За замовчуванням кодування для Python 2 - це ascii .
Марк Толонен

27
Насправді чудова ідея вбудувати високі символи унікоду у свій файл. Сумніваюсь, що носії англійської мови хочуть читати втечі Unicode у своїх рядках.
Марк Толонен

@Mark: спасибі за корекцію ASCII; Я швидко обійняв PEP ( python.org/dev/peps/pep-0263 ), і він говорить про латинську-1 в преамбулі. Я не думаю, що це ідеальна ідея вставляти у свій файл високі символи Unicode. Звичайно, якщо ви кодуєте багато неанглійських рядків у своєму вихідному файлі, це може полегшити, але ви зазвичай робите це для відображення користувачеві, і ви, мабуть, повинні визначити їх у окремому місці. І один неправильно налаштований редактор тексту може зіпсувати всі ці символи.
Кріс Б.

4
погодилися, якщо ви програмуєте додаток i18nalized, але врахуйте, чи ви китайський чи французький програміст. Це не лише рядки, а й коментарі. Чудово, що Python є гнучким з кодуванням джерела. У Python 3 можуть бути навіть символи, що не містять ASCII, у змінних імен.
Марк Толонен

23

Як уже говорили інші, # coding:вказується кодування вихідного файлу, який зберігається. Ось кілька прикладів для ілюстрації цього:

Файл, збережений на диску як cp437 (кодування моєї консолі), але кодування не оголошено

b = 'über'
u = u'über'
print b,repr(b)
print u,repr(u)

Вихід:

  File "C:\ex.py", line 1
SyntaxError: Non-ASCII character '\x81' in file C:\ex.py on line 1, but no
encoding declared; see http://www.python.org/peps/pep-0263.html for details

Виведення файлу з # coding: cp437доданим:

über '\x81ber'
über u'\xfcber'

Спочатку Python не знав кодування і скаржився на не-ASCII характер. Як тільки він знав кодування, байт-рядок отримав байти, які були насправді на диску. Для рядка Unicode Python читав \ x81, знав, що в cp437 це ü , і розшифрував його в кодовій точці Unicode для ü, яка є U + 00FC. Коли байт-рядок був надрукований, Python направляв шестинадцяткове значення 81безпосередньо на консоль. Коли надруковано рядок Unicode, Python правильно визначив кодування моєї консолі як cp437 та перевів Unicode ü у значення cp437 для ü .

Ось що відбувається з файлом, оголошеним та збереженим у UTF-8:

├╝ber '\xc3\xbcber'
über u'\xfcber'

У UTF-8 ü кодується як шістнадцятковий байт C3 BC, тому рядок байтів містить ці байти, але рядок Unicode ідентичний першому прикладу. Python прочитав два байти і правильно їх розшифрував. Python неправильно надрукував рядок байтів, тому що він послав два байти UTF-8, що представляють ü безпосередньо, на мою консоль cp437.

Тут файл оголошено cp437, але зберігається в UTF-8:

├╝ber '\xc3\xbcber'
├╝ber u'\u251c\u255dber'

Рядок байтів все ще отримав байти на диску (UTF-8 шістнадцяткових байтів C3 BC), але інтерпретував їх як два символи cp437 замість одного символу, кодованого UTF-8. Ці два символи, де переведено на код коду Unicode, і все друкується неправильно.


10

Це не встановлює формат рядка; він встановлює формат файлу. Навіть із цим заголовком "hello"є рядок байтів, а не рядок Unicode. Щоб зробити Unicode, вам доведеться використовувати u"hello"всюди. Заголовок - лише натяк на те, який формат слід використовувати при читанні .pyфайлу.


Я тоді помилявся, я вважав, що вони однакові. Тож використання для рядків Unicode - це i18n?
Оскар Карбаллал

@Oscar: Так, здебільшого. Якщо ви робили веб-сайт з Джанго чи іншим, і він мав обробляти людей з символами, що не належать до ASCII, то це ще одне можливе використання.
icktoofay

7

Визначення заголовка полягає у визначенні кодування самого коду, а не отриманих рядків під час виконання.

введення символу non-ascii типу ۲ у сценарій python без визначення заголовка utf-8 призведе до попередження

помилка


-1

Я зробив наступний модуль під назвою unicoder, щоб можна було зробити перетворення на змінних:

import sys
import os

def ustr(string):

    string = 'u"%s"'%string

    with open('_unicoder.py', 'w') as script:

        script.write('# -*- coding: utf-8 -*-\n')
        script.write('_ustr = %s'%string)

    import _unicoder
    value = _unicoder._ustr

    del _unicoder
    del sys.modules['_unicoder']

    os.system('del _unicoder.py')
    os.system('del _unicoder.pyc')

    return value

Тоді у своїй програмі ви можете зробити наступне:

# -*- coding: utf-8 -*-

from unicoder import ustr

txt = 'Hello, Unicode World'
txt = ustr(txt)

print type(txt) # <type 'unicode'>
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.