سؤال

لقد قمنا بالفعل بتشغيل قاعدة التعليمات البرمجية الخاصة بنا ضمن Python 2.6.من أجل التحضير لـ Python 3.0، بدأنا بإضافة:

from __future__ import unicode_literals

في موقعنا .py الملفات (كما نقوم بتعديلها).أتساءل عما إذا كان أي شخص آخر يقوم بذلك وقد واجه أي أخطاء غير واضحة (ربما بعد قضاء الكثير من الوقت في تصحيح الأخطاء).

هل كانت مفيدة؟

المحلول

والمصدر الرئيسي للمشاكل لقد كان العمل مع سلاسل يونيكود هو عند خلط UTF-8 سلاسل المشفرة مع تلك يونيكود.

وعلى سبيل المثال، والنظر في النصوص التالية.

و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

والناتج من تشغيل 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)

في هذا المثال، two.name هو UTF-8 سلسلة المشفرة (لا يونيكود) لأنها لم تستورد unicode_literals، وone.name هو سلسلة الشفرة. عند خلط كلا، الثعبان يحاول فك شفرة سلسلة المشفرة (على افتراض انها أسكي) وتحويله إلى يونيكود وفشل. وسوف تعمل إذا فعلت print name + two.name.decode('utf-8').

ونفس الشيء يمكن أن يحدث إذا كنت ترميز سلسلة ومحاولة مزجها في وقت لاحق. على سبيل المثال، وهذا يعمل:

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

وإخراج:

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

ولكن بعد إضافة import unicode_literals أنه لا:

# 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

وإخراج:

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)

وأنه فشل بسبب 'DEBUG: %s' هو سلسلة يونيكود وبالتالي الثعبان يحاول فك html. زوجان من الطرق لإصلاح طباعة إما تفعل print str('DEBUG: %s') % html أو print 'DEBUG: %s' % html.decode('utf-8').

وآمل أن يكون هذا يساعدك على فهم gotchas المحتملة عند استخدام سلاسل يونيكود.

نصائح أخرى

أيضًا في الإصدار 2.6 (قبل python 2.6.5 RC1+) لا تعمل حرفية Unicode بشكل جيد مع وسيطات الكلمات الرئيسية (المسألة4978):

على سبيل المثال، تعمل التعليمة البرمجية التالية بدون unicode_literals، ولكنها تفشل مع TypeError: keywords must be string إذا تم استخدام unicode_literals.

  >>> 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

ولم أجد أن إذا قمت بإضافة التوجيه unicode_literals يجب أيضا إضافة شيء من هذا القبيل:

 # -*- coding: utf-8

وإلى السطر الأول أو الثاني ملف .py. خطوط غير ذلك مثل:

 foo = "barré"

ونتيجة في خطأ مثل:

SyntaxError: Non-ASCII character '\xc3' in file mumble.py on line 198,
 but no encoding declared; see http://www.python.org/peps/pep-0263.html 
 for details

وتأخذ في الاعتبار أيضا سوف تؤثر unicode_literal ولكن ليس eval() (سلوك غير المتماثلة التي إيمهو خطأ)، وأي repr() لا يكون مساويا لeval(repr(b'\xa4')) أن b'\xa4' (كما تفعل مع بيثون 3).

ومن الناحية المثالية، التعليمة البرمجية التالية سوف تكون ثابتة، والتي يجب أن تعمل دائما، لجميع مجموعات من unicode_literals وبيثون {2.7، 3.X} الاستعمال:

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+

والتأكيد الثاني يحدث في العمل، منذ repr('\xa4') تقييمها إلى u'\xa4' في بايثون 2.7.

وهناك أكثر من ذلك.

وهناك مكتبات وbuiltins التي تتوقع السلاسل التي لا تتسامح مع يونيكود.

وهناك مثالان:

والمضمن:

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

و(esotic قليلا) لا يعمل مع unicode_literals: نوع () تتوقع سلسلة

مكتبة:

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

ولا يعمل: المكتبة WX PubSub في تتوقع نوع الرسالة سلسلة

والسابق هو مقصور على فئة معينة وثابتة بسهولة مع

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

ولكن هذا الأخير هو مدمر إذا التعليمات البرمجية مليء المكالمات إلى pub.sendMessage () (والذي هو منجم).

ودانغ ذلك، إيه؟!؟

scroll top