[Python] لماذا لا نستخدم sys.setdefaultencoding ("utf-8") في برنامج نصي؟


Answers

ليرة تركية، والدكتور

الجواب هو أبدا ! (إلا إذا كنت تعرف ما تفعله حقًا)

يمكن حل الحل 9/10 مرات مع الفهم الصحيح للتشفير / فك التشفير.

1/10 لدى الأشخاص لغة أو بيئة محددة بشكل غير صحيح ويحتاجون إلى ضبط:

PYTHONIOENCODING="UTF-8"  

في بيئتهم لإصلاح مشاكل الطباعة وحدة التحكم.

ماذا تعمل، أو ماذا تفعل؟

sys.setdefaultencoding("utf-8") (من خلال تجنب إعادة الاستخدام) يغير التشفير / فك التشفير الافتراضي المستخدم عندما تحتاج Python 2.x إلى تحويل Unicode () إلى str () (والعكس صحيح) و الترميز لم يعط. أي:

str(u"\u20AC")
unicode("€")
"{}".format(u"\u20AC") 

في Python 2.x ، يتم تعيين الترميز الافتراضي إلى ASCII وستفشل الأمثلة أعلاه مع:

UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 0: ordinal not in range(128)

(تم تكوين وحدة التحكم الخاصة بي كـ UTF-8 ، لذلك "€" = '\xe2\x82\xac' ، وبالتالي استثناء في \xe2 )

أو

UnicodeEncodeError: 'ascii' codec can't encode character u'\u20ac' in position 0: ordinal not in range(128)

sys.setdefaultencoding("utf-8") بالعمل لي ، ولكن لن يعمل بالضرورة للأشخاص الذين لا يستخدمون UTF-8. يضمن الإعداد الافتراضي لـ ASCII عدم وضع افتراضات الترميز في الشفرة

وحدة التحكم

sys.setdefaultencoding("utf-8") له أيضًا تأثير جانبي يظهر لإصلاح sys.stdout.encoding ، المستخدم عند طباعة الأحرف إلى وحدة التحكم. تستخدم Python لغة المستخدم (Linux / OS X / Un * x) أو codepage (Windows) لتعيين هذا. من حين لآخر ، يتم تقسيم لغة المستخدم وتتطلب فقط PYTHONIOENCODING لإصلاح ترميز وحدة التحكم .

مثال:

$ export LANG=en_GB.gibberish
$ python
>>> import sys
>>> sys.stdout.encoding
'ANSI_X3.4-1968'
>>> print u"\u20AC"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\u20ac' in position 0: ordinal not in range(128)
>>> exit()

$ PYTHONIOENCODING=UTF-8 python
>>> import sys
>>> sys.stdout.encoding
'UTF-8'
>>> print u"\u20AC"
€

ما هو سيئ للغاية مع sys.setdefaultencoding ("utf-8") ؟

لقد تطور الناس مقابل Python 2.x لمدة 16 عامًا على أساس أن التشفير الافتراضي هو ASCII. تمت كتابة أساليب معالجة الاستثناء UnicodeError لمعالجة سلسلة إلى Unicode التحويلات على سلاسل التي تم العثور على تحتوي على غير ASCII.

من https://anonbadger.wordpress.com/2015/06/16/why-sys-setdefaultencoding-will-break-code/

def welcome_message(byte_string):
    try:
        return u"%s runs your business" % byte_string
    except UnicodeError:
        return u"%s runs your business" % unicode(byte_string,
            encoding=detect_encoding(byte_string))

print(welcome_message(u"Angstrom (Å®)".encode("latin-1"))

قبل تعيين الإعداد الافتراضي ، لن تتمكن هذه الشفرة من فك تشفير "Å" في ترميز ascii ثم إدخال معالج الاستثناء لتخمين التشفير وتحويله بشكل صحيح إلى unicode. الطباعة: يدير Angstrom (Å®) عملك. وبمجرد قيامك بتعيين الإعداد الافتراضي إلى utf-8 ، ستجد الشفرة أن البايتة يمكن أن تفسر على أنها utf-8 ، ومن ثم سوف تقوم بتعطيل البيانات وترجع إلى هذا بدلاً من ذلك: يقوم Angstrom (Ů) بتشغيل عملك.

تغيير ما يجب أن يكون ثابتًا سيكون له تأثيرات دراماتيكية على الوحدات التي تعتمد عليها. من الأفضل فقط إصلاح البيانات القادمة من وإلى رمزك.

مشكلة المثال

في حين أن إعداد التحويل الافتراضي إلى UTF-8 ليس هو السبب الجذري في المثال التالي ، فإنه يوضح كيف يتم حجب المشاكل وكيف ، عندما يتغير تشفير الإدخال ، تتكسر الشفرة بطريقة غير واضحة: UnicodeDecodeError: 'utf8' codec can 't decode بايت 0x80 في الموضع 3131: بايت بدء غير صالح

Question

لقد رأيت بعض مخطوطات py التي تستخدم هذا في الجزء العلوي من البرنامج النصي. في أي الحالات يجب على المرء استخدامها؟

import sys
reload(sys)
sys.setdefaultencoding("utf-8")



  • الخطر الأول يكمن في reload(sys) .

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

    (This is IPython shell)
    
    In [1]: import sys
    
    In [2]: sys.stdout
    Out[2]: <colorama.ansitowin32.StreamWrapper at 0x3a2aac8>
    
    In [3]: reload(sys)
    <module 'sys' (built-in)>
    
    In [4]: sys.stdout
    Out[4]: <open file '<stdout>', mode 'w' at 0x00000000022E20C0>
    
    In [11]: import IPython.terminal
    
    In [14]: IPython.terminal.interactiveshell.sys.stdout
    Out[14]: <colorama.ansitowin32.StreamWrapper at 0x3a9aac8>
    
  • الآن ، sys.setdefaultencoding() المناسبة

    كل ما يؤثر على ذلك هو تحويل التحويل الضمني str<->unicode . الآن ، utf-8 هو الترميز الأكثر عقلًا على الكوكب (متوافق مع الإصدارات السابقة مع ASCII وجميع) ، التحويل الآن "يعمل فقط" ، ما يمكن أن تسوء؟

    حسنا ، أي شيء. وهذا هو الخطر.

    • قد يكون هناك بعض التعليمات البرمجية التي تعتمد على UnicodeError التي يتم طرحها لمدخلات غير ASCII ، أو تقوم بتحويل الترميز باستخدام معالج الأخطاء ، والذي ينتج الآن نتيجة غير متوقعة. ونظرًا لأنه يتم اختبار جميع الرموز مع الإعداد الافتراضي ، فأنت صارمة في منطقة "غير معتمدة" هنا ، ولا يمنحك أحد ضمانات حول كيفية تصرف رمزها.
    • قد ينتج الترميز نتائج غير متوقعة أو غير قابلة للاستخدام إذا لم يكن كل شيء على النظام يستخدم UTF-8 لأن Python 2 لديها بالفعل "ترميزات سلسلة افتراضية" مستقلة متعددة . (تذكر ، يجب أن يعمل البرنامج للعميل ، على معدات العميل.)
      • مرة أخرى ، أسوأ شيء هو أنك لن تعرف ذلك أبداً لأن التحويل يكون ضمنيًا - فأنت لا تعرف حقًا متى وأين يحدث ذلك. (Python Zen، koan 2 ahoy!) لن تعرف أبداً لماذا (وإذا) تعمل التعليمات البرمجية الخاصة بك على نظام واحد وتكسر على نظام آخر. (أو الأفضل من ذلك ، يعمل في IDE وفواصل في وحدة التحكم.)