Python 2.6'da unicode_literals kullanan var mı?


101

Kod tabanımızı Python 2.6 altında çalıştırdık. Python 3.0'a hazırlanmak için şunları eklemeye başladık:

__ gelecek __ den unicode_literals içe aktar

Bizim içine .pydosyaları (biz onları değiştirmek gibi). Bunu başka birinin yapıp yapmadığını ve açık olmayan herhangi bir sorunla karşılaşıp karşılaşmadığını merak ediyorum (belki de hata ayıklamaya çok zaman harcadıktan sonra).

Yanıtlar:


101

Unicode dizeleriyle çalışırken yaşadığım sorunların ana kaynağı, utf-8 kodlu dizeleri unicode olanlarla karıştırmanızdır.

Örneğin, aşağıdaki komut dosyalarını düşünün.

two.py

# encoding: utf-8
name = 'helló wörld from two'

one.py

# encoding: utf-8
from __future__ import unicode_literals
import two
name = 'helló wörld from one'
print name + two.name

Koşmanın çıktısı python one.py:

Traceback (most recent call last):
  File "one.py", line 5, in <module>
    print name + two.name
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 4: ordinal not in range(128)

Bu örnekte, two.nameiçe aktarılmadığı için utf-8 kodlu bir dizedir (unicode değil) unicode_literalsve one.namebir unicode dizesidir. Her ikisini de karıştırdığınızda, python kodlanmış dizenin kodunu çözmeye çalışır (ascii olduğunu varsayarak) ve onu unicode'a dönüştürür ve başarısız olur. Yapsaydın işe yarardı print name + two.name.decode('utf-8').

Bir dizeyi kodlar ve daha sonra karıştırmaya çalışırsanız aynı şey olabilir. Örneğin, bu işe yarar:

# encoding: utf-8
html = '<html><body>helló wörld</body></html>'
if isinstance(html, unicode):
    html = html.encode('utf-8')
print 'DEBUG: %s' % html

Çıktı:

DEBUG: <html><body>helló wörld</body></html>

Ancak ekledikten sonra import unicode_literalsYAPMAZ:

# encoding: utf-8
from __future__ import unicode_literals
html = '<html><body>helló wörld</body></html>'
if isinstance(html, unicode):
    html = html.encode('utf-8')
print 'DEBUG: %s' % html

Çıktı:

Traceback (most recent call last):
  File "test.py", line 6, in <module>
    print 'DEBUG: %s' % html
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 16: ordinal not in range(128)

Başarısız olur çünkü 'DEBUG: %s'bir unicode dizesidir ve bu nedenle python kodunu çözmeye çalışır html. Baskıyı düzeltmenin birkaç yolu ya yapıyor print str('DEBUG: %s') % htmlya da print 'DEBUG: %s' % html.decode('utf-8').

Umarım bu, unicode dizelerini kullanırken olası sorunları anlamanıza yardımcı olur.


11
Veya decode()çözümleri yerine çözümlerle gitmenizi öneririm : Unicode nesnelerini ne kadar sık ​​kullanırsanız, kod o kadar net olur, çünkü istediğiniz şey, harici olarak ima edilen bir kodlama ile bayt dizilerini değil, karakter dizilerini değiştirmek. str()encode()
Eric O Lebigot

8
Lütfen terminolojinizi düzeltin. when you mix utf-8 encoded strings with unicode onesUTF-8 ve Unicode 2 farklı kodlama değildir; Unicode bir standarttır ve UTF-8 tanımladığı kodlamalardan biridir.
Kos

11
@Kos: Sanırım "utf-8 kodlu dizeler" nesnelerini unicode (dolayısıyla kodu çözülmüş) nesnelerle karıştırmaktan bahsediyor . İlki tiptedir str, ikincisi tiptir unicode. Farklı nesneler olarak, onları toplamaya / birleştirmeye / enterpolasyon yapmaya çalışırsanız sorun ortaya çıkabilir
MestreLion

Bu python>=2.6veya için geçerli python==2.6mi?
joar

16

Ayrıca 2.6'da (python 2.6.5 RC1 + öncesi) unicode değişmezleri anahtar kelime argümanları ile iyi oynamıyor ( issue4978 ):

Örneğin aşağıdaki kod, unicode_literals olmadan çalışır, ancak TypeError ile başarısız olur: keywords must be stringeğer unicode_literals kullanılırsa.

  >>> def foo(a=None): pass
  ...
  >>> foo(**{'a':1})
  Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
      TypeError: foo() keywords must be strings

17
Bilginize, python 2.6.5 RC1 + bunu düzeltti.
Mahmoud Abdelkader

13

unicode_literalsDirektif eklerseniz, aşağıdaki gibi bir şey de eklemeniz gerektiğini fark ettim:

 # -*- coding: utf-8

.py dosyanızın ilk veya ikinci satırına. Aksi takdirde aşağıdaki gibi satırlar:

 foo = "barré"

aşağıdaki gibi bir hatayla sonuçlanır:

SyntaxError: 198. satırdaki mumble.py dosyasındaki '\ xc3' ASCII olmayan karakter,
 ancak kodlama bildirilmedi; bkz. http://www.python.org/peps/pep-0263.html
 detaylar için

5
@IanMackinnon: Python 3 dosya varsayılan tarafından UTF8 varsayar
Endolit

3
@endolith: Ama Python 2 bunu yapmaz ve yorumlarda bile ascii olmayan karakterler kullanırsanız sözdizimi hatası verir ! Yani IMHO # -*- coding: utf-8kullanmak bakılmaksızın neredeyse zorunlu açıklama olduğunu unicode_literalsya da değil
MestreLion

-*-Gerekli değildir; emacs uyumlu bir şekilde gidiyor olsaydın, ihtiyacın olacağını düşünüyorum -*- encoding: utf-8 -*-( -*-sonuna da bakın). Tek ihtiyacınız olan coding: utf-8(veya =bunun yerine : ).
Chris Morgan

2
Bu hatayı alsanız da almasanız da from __future__ import unicode_literals.
Flimm

3
Emacs uyumluluğu "kodlama" gerektirir # -*- coding: utf-8 -*- ("kodlama" veya "dosya kodlama" veya başka herhangi bir şey değil - Python, herhangi bir önekten bağımsız olarak yalnızca "kodlama" arar).
Alex Dupuy

7

Ayrıca göz önünde unicode_literaletkileyecek eval()değil ama repr()(imho bir hata olduğunu asimetrik bir davranış), yani eval(repr(b'\xa4'))eşit olmayacak b'\xa4'(Python 3 ile olduğu gibi).

İdeal olarak, aşağıdaki kod, unicode_literalsPython {2.7, 3.x} kullanımının tüm kombinasyonları için her zaman çalışması gereken bir değişmez olacaktır :

from __future__ import unicode_literals

bstr = b'\xa4'
assert eval(repr(bstr)) == bstr # fails in Python 2.7, holds in 3.1+

ustr = '\xa4'
assert eval(repr(ustr)) == ustr # holds in Python 2.7 and 3.1+

Python 2.7'de repr('\xa4')değerlendirildiği için ikinci iddia işe yarıyor u'\xa4'.


2
Sanırım buradaki en büyük problem, reprbir nesneyi yeniden oluşturmak için kullanıyor olmanız. reprDokümantasyon açıkça bu olduğunu belirten değil bir gereklilik. Bence bu, repryalnızca hata ayıklama için yararlı bir şeye indirgeniyor .
jpmc26

5

Fazlası var.

Unicode'a tolerans göstermeyen dizeler bekleyen kitaplıklar ve yerleşikler vardır.

İki örnek:

yerleşik:

myenum = type('Enum', (), enum)

(biraz esotik) unicode_literals ile çalışmaz: type () bir dizge bekler.

kütüphane:

from wx.lib.pubsub import pub
pub.sendMessage("LOG MESSAGE", msg="no go for unicode literals")

çalışmıyor: wx pubsub kitaplığı bir dize mesaj türü bekliyor.

İlki ezoteriktir ve kolayca sabitlenir

myenum = type(b'Enum', (), enum)

ancak kodunuz pub.sendMessage () 'e (benimki olan) çağrılarla doluysa ikincisi yıkıcıdır.

Dang it, ha?!?


3
Ve tür öğeleri metasınıflara da sızıyor - bu nedenle Django'da bildirdiğiniz tüm dizeler şöyle class Meta:olmalıdırb'field_name'
Hamish Downer

2
Evet ... benim durumumda, tüm sendMessage dizelerini aramanın ve b 'sürümleriyle değiştirmenin çabaya değer olduğunu fark ettim. Korkunç "kod çözme" istisnasından kaçınmak istiyorsanız, programınızda kesinlikle unicode kullanmak, gerektiğinde girdi ve çıktıya dönüştürmek gibisi yoktur (konuyla ilgili okuduğum bazı makalelerde bahsedilen "unicode sandviç"). Genel olarak, unicode_literals benim için büyük bir kazanç oldu ...
GreenAsJade

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.