Neden unicode'u python'da dizeye göre bildirelim?


122

Hala python öğreniyorum ve bir şüphem var:

Python 2.6.x'te genellikle bu şekilde dosya başlığında kodlama bildiririm ( PEP 0263'teki gibi )

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

Bundan sonra dizelerim her zamanki gibi yazılıyor:

a = "A normal string without declared Unicode"

Ancak her zaman bir python proje kodu gördüğümde, kodlama başlıkta bildirilmiyor. Bunun yerine, her dizede şu şekilde bildirilir:

a = u"A string with declared Unicode"

Fark ne? Bunun amacı nedir? Python 2.6.x'in varsayılan olarak ASCII kodlamasını ayarladığını biliyorum, ancak başlık bildirimi tarafından geçersiz kılınabilir, öyleyse dizge başına bildiriminin amacı nedir?

Eklenti: Dosya kodlamasını dize kodlamasıyla karıştırmışım gibi görünüyor. Açıkladığınız için teşekkürler :)


6
# coding: utf8yeterince iyi, gerek yok-*-
denizanası

1
@jellyfish Yazmak istediğinizi varsayıyorum # coding: utf-8.
Samuel Harmer

Yanıtlar:


167

Diğerlerinin de bahsettiği gibi bunlar iki farklı şey.

Belirttiğinizde# -*- coding: utf-8 -*- , Python'a kaydettiğiniz kaynak dosyanın olduğunu söylüyorsunuz utf-8. Python 2 için varsayılan ASCII'dir (Python 3 için budur utf-8). Bu sadece yorumlayıcının dosyadaki karakterleri nasıl okuyacağını etkiler.

Genel olarak, kodlama ne olursa olsun dosyanıza yüksek Unicode karakterleri yerleştirmek muhtemelen en iyi fikir değildir; her iki kodlamada da çalışan dize unicode kaçışlarını kullanabilirsiniz.


uÖnünde bir dizeyi bildirdiğinizde , örneğin u'This is a string', Python derleyicisine dizenin bayt değil, Unicode olduğunu söyler. Bu, çoğunlukla şeffaf bir şekilde tercüman tarafından ele alınır; en belirgin fark, artık dizeye unicode karakterleri gömebilmenizdir (yani u'\u2665', artık yasaldır). from __future__ import unicode_literalsVarsayılan yapmak için kullanabilirsiniz .

Bu yalnızca Python 2 için geçerlidir; Python 3'te varsayılan değer Unicode'dur ve bönünde bir belirtmeniz gerekir (örneğin b'These are bytes', bir bayt dizisi bildirmek için).


Açıklama için teşekkürler! Bunu kabul edildi olarak ayarlayacağım çünkü en eksiksiz olanı :)
Oscar Carballal

2
Python 2 için varsayılan kaynak kodlaması ascii'dir .
Mark Tolonen

27
Dosyanıza yüksek unicode karakterleri yerleştirmek aslında harika bir fikirdir. İngilizce konuşmayanların dizelerinde unicode kaçışlarını okumak istediğinden şüpheliyim.
Mark Tolonen

@Mark: ASCII düzeltmesi için teşekkürler; PEP'yi ( python.org/dev/peps/pep-0263 ) hızlıca gözden geçirdim ve giriş bölümünde Latin-1'den bahsediyor. Dosyanıza çoğu durumda yüksek unicode karakterleri yerleştirmenin iyi bir fikir olduğunu sanmıyorum. Elbette, kaynak dosyanızda çok sayıda İngilizce olmayan dizeyi kodluyorsanız, bunu kolaylaştırabilir, ancak bunu genellikle kullanıcıya göstermek için yaparsınız ve muhtemelen bunları yine de ayrı bir yerde tanımlamalısınız. Ve tek bir yanlış yapılandırılmış metin editörü tüm bu karakterleri bozabilir.
Chris B.

4
i18nalized bir uygulama programlıyorsanız, ancak Çinli veya Fransız bir programcı olup olmadığınızı düşünün. Sadece dizeler değil, yorumlar da. Python'un kaynak kodlamalarında esnek olması harika. Python 3, değişken adlarında ASCII olmayan karakterlere bile sahip olabilir.
Mark Tolonen

23

Diğerlerinin söylediği gibi, # coding:kaynak dosyanın kaydedildiği kodlamayı belirtir. Bunu açıklamak için bazı örnekler aşağıda verilmiştir:

Diske cp437 (konsol kodlamam) olarak kaydedilmiş bir dosya, ancak kodlama bildirilmedi

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

Çıktı:

  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: cp437Eklenen dosyanın çıktısı :

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

İlk başta Python, kodlamayı bilmiyordu ve ASCII olmayan karakterden şikayet etti. Kodlamayı öğrendikten sonra, bayt dizesi aslında diskte bulunan baytları aldı. Unicode dizesi için, Python \ x81 okudu, cp437'de bunun bir ü olduğunu biliyordu ve ü için U + 00FC olan Unicode kod noktasına kodunu çözdü. Bayt dizesi yazdırıldığında, Python onaltılık değeri 81doğrudan konsola gönderdi . Unicode dize baskılı zaman, Python doğru cp437 olarak benim konsol kodlamayı tespit ve Unicode tercüme ü için cp437 değerine ü .

UTF-8'de bildirilen ve kaydedilen bir dosyada şunlar olur:

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

UTF-8'de ü , onaltılık bayt olarak kodlanır C3 BC, bu nedenle bayt dizesi bu baytları içerir, ancak Unicode dizesi ilk örnekle aynıdır. Python iki baytı okudu ve doğru şekilde çözdü. Python, bayt dizesini yanlış yazdırdı, çünkü ü temsil eden iki UTF-8 baytı doğrudan cp437 konsoluma gönderdi.

Burada dosya cp437 olarak bildirilir, ancak UTF-8 olarak kaydedilir:

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

Bayt dizesi, baytları diskte C3 BCtutmaya devam ediyor (UTF-8 onaltılık bayt ), ancak bunları tek bir UTF-8 ile kodlanmış karakter yerine iki cp437 karakteri olarak yorumladı. Unicode kod noktalarına çevrilen bu iki karakter ve her şey yanlış yazdırılır.


10

Bu, dizenin biçimini belirlemez; dosyanın formatını ayarlar. Bu başlıkla bile "hello", bir bayt dizesidir, bir Unicode dizesi değildir. Bunu Unicode yapmak için u"hello"her yerde kullanmanız gerekecek . Başlık, .pydosyayı okurken hangi formatın kullanılacağına dair bir ipucu .


O zaman yanılmışım, aynı olduklarını düşünmüştüm. Yani unicode dizeleri için kullanım i18n mi?
Oscar Carballal

@Oscar: Evet, çoğunlukla. Django veya başka bir şeyle bir web sitesi yapıyorsanız ve ASCII olmayan karakterlere sahip insanları ele alması gerekiyorsa, bu başka bir olası kullanımdır.
icktoofay

7

Başlık tanımı, çalışma zamanında sonuçta ortaya çıkan dizeleri değil, kodun kendisinin kodlamasını tanımlamaktır.

utf-8 başlık tanımı olmadan python betiğine like gibi ascii olmayan bir karakter koymak bir uyarı verecektir

hata


-1

Değişkenler üzerinde dönüşümü yapabilmek için aşağıdaki modülü unicoder yaptım:

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

Daha sonra programınızda şunları yapabilirsiniz:

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

from unicoder import ustr

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

print type(txt) # <type 'unicode'>
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.