Mengapa mendeklarasikan unicode dengan string dengan python?

122

Saya masih belajar python dan saya ragu:

Di python 2.6.x saya biasanya mendeklarasikan pengkodean di header file seperti ini (seperti di PEP 0263 )

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

Setelah itu, string saya ditulis seperti biasa:

a = "A normal string without declared Unicode"

Tetapi setiap kali saya melihat kode proyek python, pengkodeannya tidak dideklarasikan di header. Sebaliknya, itu dideklarasikan di setiap string seperti ini:

a = u"A string with declared Unicode"

Apa bedanya? Apa tujuannya ini? Saya tahu Python 2.6.x menetapkan pengkodean ASCII secara default, tetapi dapat diganti dengan deklarasi header, jadi apa gunanya deklarasi per string?

Tambahan: Sepertinya saya telah mencampur pengkodean file dengan pengkodean string. Terima kasih telah menjelaskannya :)

Oscar Carballal
sumber
6
# coding: utf8cukup baik, tidak perlu-*-
ubur
1
@Jellyfish Saya menganggap Anda bermaksud mengetik # coding: utf-8.
Samuel Harmer
Seharusnya #coding=utf-8. python.org/dev/peps/pep-0263
Guangtong Shen

Jawaban:

167

Itu adalah dua hal yang berbeda, seperti yang disebutkan orang lain.

Saat Anda menentukan# -*- coding: utf-8 -*- , Anda memberi tahu Python bahwa file sumber yang Anda simpan adalah utf-8. Default untuk Python 2 adalah ASCII (untuk Python 3 itu utf-8). Ini hanya memengaruhi cara penerjemah membaca karakter dalam file.

Secara umum, mungkin bukan ide terbaik untuk menyematkan karakter unicode tinggi ke dalam file Anda apa pun pengkodeannya; Anda dapat menggunakan pelolosan unicode string, yang berfungsi di salah satu enkode.


Saat Anda mendeklarasikan string dengan uin front , like u'This is a string', ini memberi tahu compiler Python bahwa string tersebut adalah Unicode, bukan byte. Hal ini sebagian besar ditangani secara transparan oleh penerjemah; perbedaan yang paling jelas adalah sekarang Anda dapat menyematkan karakter unicode dalam string (yang u'\u2665'sekarang legal). Anda dapat menggunakannya from __future__ import unicode_literalsuntuk menjadikannya default.

Ini hanya berlaku untuk Python 2; di Python 3 defaultnya adalah Unicode, dan Anda perlu menentukan a bdi depan (seperti b'These are bytes', untuk menyatakan urutan byte).

Chris B.
sumber
Terima kasih untuk penjelasannya! Saya akan menetapkan ini sebagai diterima karena adalah yang paling lengkap :)
Oscar Carballal
2
Pengkodean sumber default untuk Python 2 adalah ascii .
Mark Tolonen
27
Sebenarnya ide bagus untuk menyematkan karakter unicode tinggi ke dalam file Anda. Saya ragu penutur non-Inggris ingin membaca pelolosan unicode dalam string mereka.
Mark Tolonen
@ Mark: Terima kasih atas koreksi ASCII; Saya dengan cepat membaca PEP ( python.org/dev/peps/pep-0263 ) dan berbicara tentang Latin-1 di bagian pembukaan. Saya tidak berpikir itu ide yang bagus untuk menanamkan karakter unicode tinggi di file Anda dalam banyak kasus. Tentu saja, jika Anda mengkodekan banyak string non-Inggris di file sumber Anda, ini dapat membuatnya lebih mudah, tetapi Anda biasanya melakukannya untuk ditampilkan kepada pengguna, dan Anda mungkin harus mendefinisikannya di tempat terpisah. Dan satu editor teks yang salah konfigurasi dapat merusak semua karakter itu.
Chris B.
4
setuju jika Anda memprogram aplikasi i18nalized, tetapi pertimbangkan jika Anda seorang programmer Cina atau Prancis. Bukan hanya senarnya, tapi juga komentarnya. Bagus sekali Python fleksibel dengan pengkodean sumber. Python 3 bahkan dapat memiliki karakter non-ASCII dalam nama variabel.
Mark Tolonen
23

Seperti yang dikatakan orang lain, # coding:menentukan pengkodean tempat file sumber disimpan. Berikut adalah beberapa contoh untuk menggambarkan hal ini:

File disimpan pada disk sebagai cp437 (pengkodean konsol saya), tetapi tidak ada pengkodean yang dinyatakan

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

Keluaran:

  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

Output file dengan # coding: cp437menambahkan:

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

Awalnya, Python tidak mengetahui pengkodeannya dan mengeluhkan karakter non-ASCII. Setelah mengetahui pengkodeannya, string byte mendapatkan byte yang sebenarnya ada di disk. Untuk string Unicode, Python membaca \ x81, mengetahui bahwa di cp437 itu adalah ü , dan mendekodekannya menjadi titik kode Unicode untuk ü yaitu U + 00FC. Ketika string byte dicetak, Python mengirim nilai hex 81ke konsol secara langsung. Ketika string Unicode dicetak, Python dengan benar mendeteksi pengkodean konsol saya sebagai cp437 dan menerjemahkan Unicode ü ke nilai cp437 untuk ü .

Inilah yang terjadi dengan file yang dideklarasikan dan disimpan dalam UTF-8:

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

Dalam UTF-8, ü dikodekan sebagai hex byte C3 BC, sehingga string byte berisi byte tersebut, tetapi string Unicode identik dengan contoh pertama. Python membaca dua byte dan mendekodekannya dengan benar. Python salah mencetak string byte, karena mengirim dua byte UTF-8 yang mewakili ü langsung ke konsol cp437 saya.

Di sini file tersebut dinyatakan sebagai cp437, tetapi disimpan dalam UTF-8:

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

String byte masih mendapatkan byte pada disk (UTF-8 hex byte C3 BC), tetapi menafsirkannya sebagai dua karakter cp437 alih-alih satu karakter yang dikodekan UTF-8. Kedua karakter yang diterjemahkan ke poin kode Unicode, dan semuanya dicetak dengan tidak benar.

Mark Tolonen
sumber
10

Itu tidak mengatur format string; itu mengatur format file. Bahkan dengan header itu, "hello"adalah string byte, bukan string Unicode. Untuk membuatnya menjadi Unicode, Anda harus menggunakannya di u"hello"mana saja. Header hanyalah petunjuk tentang format apa yang akan digunakan saat membaca .pyfile.

icktoofay
sumber
Saya keliru saat itu, saya pikir mereka sama. Jadi penggunaan string unicode adalah i18n?
Oscar Carballal
@ Oscar: Ya, untuk sebagian besar. Jika Anda membuat situs web dengan Django atau sesuatu dan itu harus menangani orang dengan karakter non-ASCII, maka itu kemungkinan penggunaan lain.
icktoofay
7

Definisi header adalah untuk menentukan pengkodean kode itu sendiri, bukan string yang dihasilkan saat runtime.

menempatkan karakter non-ascii seperti ۲ di skrip python tanpa definisi header utf-8 akan memunculkan peringatan

kesalahan

ebt
sumber
-1

Saya membuat modul berikut yang disebut unicoder untuk dapat melakukan transformasi pada variabel:

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

Kemudian dalam program Anda, Anda dapat melakukan hal berikut:

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

from unicoder import ustr

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

print type(txt) # <type 'unicode'>
tecnobillo
sumber