Bagaimana ini bukan duplikat tepat dari Bahaya sys.setdefaultencoding ('utf-8') ? Meskipun ini (2010) bertanya sebelum itu (2015)? Tetapi pertanyaan itu juga memiliki jawaban yang bagus. Apa yang harus dilakukan? Juga, untuk menjadi jelas, pertanyaan ini hanya masuk akal pada Python 2 bukan 3, namun itu tidak ditandai atau disebutkan.
Sesuai dokumentasi: Ini memungkinkan Anda untuk beralih dari ASCII default ke penyandian lain seperti UTF-8, yang akan digunakan oleh runtime Python setiap kali harus mendekode buffer string ke unicode.
Fungsi ini hanya tersedia pada waktu mulai Python, ketika Python memindai lingkungan. Itu harus disebut dalam modul sistem-lebar sitecustomize.py,, Setelah modul ini dievaluasi, setdefaultencoding()fungsi dihapus dari sysmodul.
Satu-satunya cara untuk benar-benar menggunakannya adalah dengan retas retas yang mengembalikan atribut.
Juga, penggunaan sys.setdefaultencoding()selalu tidak disarankan , dan telah menjadi larangan di py3k. Pengkodean py3k adalah terprogram untuk "utf-8" dan mengubahnya menimbulkan kesalahan.
Saya ingin menambahkan bahwa pengkodean default juga digunakan untuk pengkodean (saat menulis ke sys.stdoutketika memiliki Nonepengkodean, seperti ketika mengarahkan output dari program Python).
Eric O Lebigot
14
+1 untuk "penggunaan sys.setdefaultencoding()selalu tidak disarankan"
jfs
7
'kabel-kabel ke utf-8' tidak benar, itu tidak bawaan dan tidak selalu UTF-8. LC_ALL=en_US.UTF-8 python3 -c 'import sys; print(sys.stdout.encoding)'memberi UTF-8tetapi LC_ALL=C python3 -c 'import sys; print(sys.stdout.encoding)'memberi ANSI_X3.4-1968(atau mungkin sesuatu yang lain)
Tino
7
@Tino, pengkodean konsol terpisah dari pengodean default.
Alastair McCormack
59
tl; dr
Jawabannya TIDAK PERNAH ! (kecuali jika Anda benar-benar tahu apa yang Anda lakukan)
9/10 kali solusinya dapat diselesaikan dengan pemahaman yang tepat tentang pengkodean / decoding.
1/10 orang memiliki lokal atau lingkungan yang tidak didefinisikan dengan benar dan perlu mengatur:
PYTHONIOENCODING="UTF-8"
di lingkungan mereka untuk memperbaiki masalah pencetakan konsol.
Apa fungsinya?
sys.setdefaultencoding("utf-8")(dipukul untuk menghindari penggunaan kembali) mengubah pengkodean / dekode default yang digunakan setiap kali Python 2.x perlu mengubah Unicode () ke str () (dan sebaliknya) dan pengkodean tidak diberikan. Yaitu:
str(u"\u20AC")
unicode("€")"{}".format(u"\u20AC")
Dalam Python 2.x, penyandian default diatur ke ASCII dan contoh di atas akan gagal dengan:
UnicodeDecodeError:'ascii' codec can't decode byte 0xe2 in position 0: ordinal not in range(128)
(Konsol saya dikonfigurasi sebagai UTF-8, jadi "€" = '\xe2\x82\xac', karenanya pengecualian pada \xe2)
atau
UnicodeEncodeError:'ascii' codec can't encode character u'\u20ac' in position 0: ordinal not in range(128)
sys.setdefaultencoding("utf-8")akan memungkinkan ini bekerja untuk saya , tetapi tidak akan selalu berfungsi untuk orang yang tidak menggunakan UTF-8. Default ASCII memastikan bahwa asumsi pengkodean tidak dimasukkan ke dalam kode
Menghibur
sys.setdefaultencoding("utf-8")juga memiliki efek samping muncul untuk memperbaiki sys.stdout.encoding, digunakan saat mencetak karakter ke konsol. Python menggunakan lokal pengguna (Linux / OS X / Un * x) atau codepage (Windows) untuk mengatur ini. Kadang-kadang, lokal pengguna rusak dan hanya perlu PYTHONIOENCODINGmemperbaiki pengkodean konsol .
Contoh:
$ 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"
€
Apa yang buruk dengan sys.setdefaultencoding ("utf-8") ?
Orang-orang telah mengembangkan terhadap Python 2.x selama 16 tahun dengan pemahaman bahwa penyandian default adalah ASCII. UnicodeErrormetode penanganan pengecualian telah ditulis untuk menangani konversi string ke Unicode pada string yang ternyata mengandung non-ASCII.
def welcome_message(byte_string):try:return u"%s runs your business"% byte_string
exceptUnicodeError:return u"%s runs your business"% unicode(byte_string,
encoding=detect_encoding(byte_string))print(welcome_message(u"Angstrom (Å®)".encode("latin-1"))
Sebelum menetapkan defaultencoding, kode ini tidak akan dapat men-decode "Å" dalam encoding ascii dan kemudian akan memasukkan pengendali pengecualian untuk menebak encoding dan mengubahnya dengan benar menjadi unicode. Mencetak: Angstrom (Å®) menjalankan bisnis Anda. Setelah Anda menetapkan defaultencoding ke utf-8 kode akan menemukan bahwa byte_string dapat diartikan sebagai utf-8 dan itu akan memotong-motong data dan mengembalikan ini sebagai gantinya: Angstrom (Ů) menjalankan bisnis Anda.
Mengubah apa yang seharusnya konstan akan memiliki efek dramatis pada modul yang Anda andalkan. Lebih baik memperbaiki data yang masuk dan keluar dari kode Anda.
Meskipun ada kejutan di sys.setdefaultencoding("utf-8")dalamnya, ada baiknya membuat kode berperilaku lebih seperti Python 3. Sekarang 2017. Bahkan ketika Anda menulis jawabannya pada tahun 2015, saya pikir sudah lebih baik untuk melihat ke depan daripada ke belakang. Itu sebenarnya solusi paling sederhana bagi saya, ketika saya menemukan kode saya berperilaku berbeda di Python 2 tergantung pada apakah output diarahkan (masalah yang sangat buruk untuk Python 2). Tak perlu dikatakan, saya sudah punya # coding: utf-8, dan saya tidak perlu ada solusi untuk Python 3 (saya benar-benar harus menutupi setdefaultencodingcek menggunakan versi).
Yongwei Wu
Itu bagus dan berfungsi untuk Anda tetapi sys.setdefaultencoding("utf-8")tidak membuat kode Py 2.x Anda kompatibel dengan Python 3. Juga tidak memperbaiki modul eksternal yang menganggap pengkodean default adalah ASCII. Membuat kode Anda kompatibel dengan Python 3 sangat sederhana dan tidak memerlukan peretasan jahat ini. Misalnya mengapa ini menyebabkan masalah yang sangat nyata, lihat pengalaman saya dengan Amazon mengacaukan asumsi ini: stackoverflow.com/questions/39465220/…
Alastair McCormack
1
@AlastairMcCormack you rock, Situs saya sudah sejak berbulan-bulan dan tidak tahu apa yang harus dilakukan. Akhirnya, PYTHONIOENCODING="UTF-8"membantu lingkungan Python2.7 Django-1.11 saya. Terima kasih.
sam
Saya tahu Anda menyalin contohnya, tetapi saya dapat menemukan paket apa yang dimiliki detect_encoding.
dlamblin
@ dlamblin Contoh kode adalah untuk membuktikan kutipan dan tidak seharusnya digunakan dalam kode Anda. Bayangkan itu detect_encodingadalah metode yang bisa mendeteksi pengkodean string berdasarkan petunjuk bahasa.
Alastair McCormack
18
#!/usr/bin/env python#-*- coding: utf-8 -*-
u = u'moçambique'print u.encode("utf-8")print u
chmod +x test.py
./test.py
moçambique
moçambique
./test.py > output.txt
Traceback(most recent call last):File"./test.py", line 5,in<module>print u
UnicodeEncodeError:'ascii' codec can't encode character
u'\xe7' in position 2: ordinal not in range(128)
pada shell bekerja, mengirim ke sdtout tidak, jadi itu adalah satu solusi, untuk menulis ke stdout
Saya membuat pendekatan lain, yang tidak berjalan jika sys.stdout.encoding tidak mendefinisikan, atau dengan kata lain, perlu ekspor PYTHONIOENCODING = UTF-8 terlebih dahulu untuk menulis ke stdout.
import sys
if(sys.stdout.encoding isNone):print>> sys.stderr,"please set python env PYTHONIOENCODING=UTF-8, example: export PYTHONIOENCODING=UTF-8, when write to stdout."
exit(1)
Ini tidak menjawab pertanyaan seperti yang ditanyakan. Melainkan beberapa pemikiran tangensial pada subjek.
ivan_pozdeev
3
Bahaya pertama terletak pada reload(sys).
Ketika Anda memuat ulang modul, Anda sebenarnya mendapatkan dua salinan dari modul di runtime Anda. Modul lama adalah objek Python seperti yang lainnya, dan tetap hidup selama ada referensi untuk itu. Jadi, setengah dari objek akan menunjuk ke modul lama, dan setengah ke yang baru. Ketika Anda membuat beberapa perubahan, Anda tidak akan pernah melihatnya datang ketika beberapa objek acak tidak melihat perubahan:
(ThisisIPython 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]:importIPython.terminal
In[14]:IPython.terminal.interactiveshell.sys.stdout
Out[14]:<colorama.ansitowin32.StreamWrapper at 0x3a9aac8>
Mungkin ada beberapa kode yang bergantung pada UnicodeErroryang dilemparkan untuk input non-ASCII, atau melakukan transcoding dengan penangan kesalahan, yang sekarang menghasilkan hasil yang tidak terduga. Dan karena semua kode diuji dengan pengaturan default, Anda benar-benar berada di wilayah "tidak didukung" di sini , dan tidak ada yang memberi Anda jaminan tentang bagaimana kode mereka akan berperilaku.
Sekali lagi, hal terburuknya adalah Anda tidak akan pernah tahu itu karena konversi itu implisit - Anda tidak benar-benar tahu kapan dan di mana itu terjadi. (Python Zen, koan 2 ahoy!) Anda tidak akan pernah tahu mengapa (dan jika) kode Anda bekerja pada satu sistem dan merusak yang lain. (Atau lebih baik lagi, bekerja di IDE dan istirahat di konsol.)
Jawaban:
Sesuai dokumentasi: Ini memungkinkan Anda untuk beralih dari ASCII default ke penyandian lain seperti UTF-8, yang akan digunakan oleh runtime Python setiap kali harus mendekode buffer string ke unicode.
Fungsi ini hanya tersedia pada waktu mulai Python, ketika Python memindai lingkungan. Itu harus disebut dalam modul sistem-lebar
sitecustomize.py
,, Setelah modul ini dievaluasi,setdefaultencoding()
fungsi dihapus darisys
modul.Satu-satunya cara untuk benar-benar menggunakannya adalah dengan retas retas yang mengembalikan atribut.
Juga, penggunaan
sys.setdefaultencoding()
selalu tidak disarankan , dan telah menjadi larangan di py3k. Pengkodean py3k adalah terprogram untuk "utf-8" dan mengubahnya menimbulkan kesalahan.Saya menyarankan beberapa petunjuk untuk membaca:
sumber
sys.stdout
ketika memilikiNone
pengkodean, seperti ketika mengarahkan output dari program Python).sys.setdefaultencoding()
selalu tidak disarankan"UTF-8
.LC_ALL=en_US.UTF-8 python3 -c 'import sys; print(sys.stdout.encoding)'
memberiUTF-8
tetapiLC_ALL=C python3 -c 'import sys; print(sys.stdout.encoding)'
memberiANSI_X3.4-1968
(atau mungkin sesuatu yang lain)tl; dr
Jawabannya TIDAK PERNAH ! (kecuali jika Anda benar-benar tahu apa yang Anda lakukan)
9/10 kali solusinya dapat diselesaikan dengan pemahaman yang tepat tentang pengkodean / decoding.
1/10 orang memiliki lokal atau lingkungan yang tidak didefinisikan dengan benar dan perlu mengatur:
di lingkungan mereka untuk memperbaiki masalah pencetakan konsol.
Apa fungsinya?
(dipukul untuk menghindari penggunaan kembali) mengubah pengkodean / dekode default yang digunakan setiap kali Python 2.x perlu mengubah Unicode () ke str () (dan sebaliknya) dan pengkodean tidak diberikan. Yaitu:sys.setdefaultencoding("utf-8")
Dalam Python 2.x, penyandian default diatur ke ASCII dan contoh di atas akan gagal dengan:
(Konsol saya dikonfigurasi sebagai UTF-8, jadi
"€" = '\xe2\x82\xac'
, karenanya pengecualian pada\xe2
)atau
akan memungkinkan ini bekerja untuk saya , tetapi tidak akan selalu berfungsi untuk orang yang tidak menggunakan UTF-8. Default ASCII memastikan bahwa asumsi pengkodean tidak dimasukkan ke dalam kodesys.setdefaultencoding("utf-8")
Menghibur
juga memiliki efek samping muncul untuk memperbaikisys.setdefaultencoding("utf-8")
sys.stdout.encoding
, digunakan saat mencetak karakter ke konsol. Python menggunakan lokal pengguna (Linux / OS X / Un * x) atau codepage (Windows) untuk mengatur ini. Kadang-kadang, lokal pengguna rusak dan hanya perluPYTHONIOENCODING
memperbaiki pengkodean konsol .Contoh:
Apa yang buruk dengan
sys.setdefaultencoding ("utf-8")?Orang-orang telah mengembangkan terhadap Python 2.x selama 16 tahun dengan pemahaman bahwa penyandian default adalah ASCII.
UnicodeError
metode penanganan pengecualian telah ditulis untuk menangani konversi string ke Unicode pada string yang ternyata mengandung non-ASCII.Dari https://anonbadger.wordpress.com/2015/06/16/why-sys-setdefaultencoding-will-break-code/
Mengubah apa yang seharusnya konstan akan memiliki efek dramatis pada modul yang Anda andalkan. Lebih baik memperbaiki data yang masuk dan keluar dari kode Anda.
Contoh masalah
Sementara pengaturan defaultencoding ke UTF-8 bukan penyebab utama dalam contoh berikut, ini menunjukkan bagaimana masalah ditutup dan bagaimana, ketika input encoding berubah, kode tersebut terputus dengan cara yang tidak jelas: UnicodeDecodeError: codec 'utf8' dapat mendekode byte 0x80 di posisi 3131: byte awal tidak valid
sumber
sys.setdefaultencoding("utf-8")
dalamnya, ada baiknya membuat kode berperilaku lebih seperti Python 3. Sekarang 2017. Bahkan ketika Anda menulis jawabannya pada tahun 2015, saya pikir sudah lebih baik untuk melihat ke depan daripada ke belakang. Itu sebenarnya solusi paling sederhana bagi saya, ketika saya menemukan kode saya berperilaku berbeda di Python 2 tergantung pada apakah output diarahkan (masalah yang sangat buruk untuk Python 2). Tak perlu dikatakan, saya sudah punya# coding: utf-8
, dan saya tidak perlu ada solusi untuk Python 3 (saya benar-benar harus menutupisetdefaultencoding
cek menggunakan versi).sys.setdefaultencoding("utf-8")
tidak membuat kode Py 2.x Anda kompatibel dengan Python 3. Juga tidak memperbaiki modul eksternal yang menganggap pengkodean default adalah ASCII. Membuat kode Anda kompatibel dengan Python 3 sangat sederhana dan tidak memerlukan peretasan jahat ini. Misalnya mengapa ini menyebabkan masalah yang sangat nyata, lihat pengalaman saya dengan Amazon mengacaukan asumsi ini: stackoverflow.com/questions/39465220/…PYTHONIOENCODING="UTF-8"
membantu lingkungan Python2.7 Django-1.11 saya. Terima kasih.detect_encoding
.detect_encoding
adalah metode yang bisa mendeteksi pengkodean string berdasarkan petunjuk bahasa.pada shell bekerja, mengirim ke sdtout tidak, jadi itu adalah satu solusi, untuk menulis ke stdout
Saya membuat pendekatan lain, yang tidak berjalan jika sys.stdout.encoding tidak mendefinisikan, atau dengan kata lain, perlu ekspor PYTHONIOENCODING = UTF-8 terlebih dahulu untuk menulis ke stdout.
jadi, dengan menggunakan contoh yang sama:
akan bekerja
sumber
Bahaya pertama terletak pada
reload(sys)
.Ketika Anda memuat ulang modul, Anda sebenarnya mendapatkan dua salinan dari modul di runtime Anda. Modul lama adalah objek Python seperti yang lainnya, dan tetap hidup selama ada referensi untuk itu. Jadi, setengah dari objek akan menunjuk ke modul lama, dan setengah ke yang baru. Ketika Anda membuat beberapa perubahan, Anda tidak akan pernah melihatnya datang ketika beberapa objek acak tidak melihat perubahan:
Sekarang,
sys.setdefaultencoding()
tepatSemua yang dipengaruhinya adalah konversi implisit
str<->unicode
. Sekarang,utf-8
apakah penyandian paling baik di planet ini (kompatibel dengan ASCII dan yang lainnya), konversi sekarang "hanya berfungsi", apa yang mungkin salah?Yah, apapun. Dan itu adalah bahayanya.
UnicodeError
yang dilemparkan untuk input non-ASCII, atau melakukan transcoding dengan penangan kesalahan, yang sekarang menghasilkan hasil yang tidak terduga. Dan karena semua kode diuji dengan pengaturan default, Anda benar-benar berada di wilayah "tidak didukung" di sini , dan tidak ada yang memberi Anda jaminan tentang bagaimana kode mereka akan berperilaku.sumber