Saya memiliki banyak masalah "tidak dapat menyandikan" dan "tidak dapat memecahkan kode" dengan Python ketika saya menjalankan aplikasi saya dari konsol. Tapi di Eclipse PyDev IDE, pengkodean karakter default disetel ke UTF-8 , dan saya baik-baik saja.
Saya mencari-cari pengaturan pengkodean default, dan orang-orang mengatakan bahwa Python menghapus sys.setdefaultencoding
fungsi saat startup, dan kami tidak dapat menggunakannya.
Jadi apa solusi terbaiknya?
The best solution is to learn to use encode and decode correctly instead of using hacks.
Ini tentu saja dimungkinkan dengan python2 dengan biaya selalu mengingat untuk melakukannya / secara konsisten menggunakan antarmuka Anda sendiri. Pengalaman saya menunjukkan bahwa ini menjadi sangat bermasalah saat Anda menulis kode yang ingin Anda gunakan dengan python2 dan python3.Jawaban:
Berikut adalah metode sederhana (peretasan) yang mengembalikan
setdefaultencoding()
fungsi yang telah dihapus darisys
:import sys # sys.setdefaultencoding() does not exist, here! reload(sys) # Reload does the trick! sys.setdefaultencoding('UTF8')
(Catatan untuk Python 3.4+:
reload()
ada diimportlib
perpustakaan.)Ini bukan hal yang aman untuk dilakukan : ini jelas merupakan peretasan, karena
sys.setdefaultencoding()
sengaja dihapus darisys
saat Python dimulai. Mengaktifkannya kembali dan mengubah pengkodean default dapat merusak kode yang bergantung pada ASCII sebagai default (kode ini dapat dari pihak ketiga, yang umumnya membuat perbaikan tidak mungkin atau berbahaya).sumber
LC_CTYPE
(atau dalam sebuah aplikasi, periksa apakah sudah diatur dengan benar dan batalkan dengan pesan kesalahan yang berarti).LC_CTYPE=C python -c 'import locale; print( locale.getpreferredencoding())'
Jika Anda mendapatkan kesalahan ini saat mencoba menyalurkan / mengalihkan output skrip Anda
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
Cukup ekspor PYTHONIOENCODING di konsol dan kemudian jalankan kode Anda.
export PYTHONIOENCODING=utf8
sumber
LC_CTYPE
ke sesuatu yang masuk akal sebagai gantinya. Itu membuat semua program lain senang juga.PYTHONIOENCODING=utf8
bukan defaultnya. Ini membuat skrip rusak hanya karenaLC_ALL=C
Set LC_CTYPE to something sensible instead
Ini adalah saran yang masuk akal. Ini tidak berfungsi dengan baik ketika Anda mencoba mendistribusikan kode yang hanya berfungsi di sistem orang lain.C.utf8
lokal untuk menyediakan C. glibc upstream yang bekerja untuk menambahkannya, jadi mungkin kita tidak harus menyalahkan Python karena menghormati pengaturan lokal \…?A) Untuk mengontrol
sys.getdefaultencoding()
keluaran:python -c 'import sys; print(sys.getdefaultencoding())'
ascii
Kemudian
echo "import sys; sys.setdefaultencoding('utf-16-be')" > sitecustomize.py
dan
PYTHONPATH=".:$PYTHONPATH" python -c 'import sys; print(sys.getdefaultencoding())'
utf-16-be
Anda dapat menempatkan sitecustomize.py Anda lebih tinggi di
PYTHONPATH
.Anda juga mungkin ingin mencoba
reload(sys).setdefaultencoding
@EOLB) Untuk mengontrol
stdin.encoding
danstdout.encoding
Anda ingin mengaturPYTHONIOENCODING
:python -c 'import sys; print(sys.stdin.encoding, sys.stdout.encoding)'
ascii ascii
Kemudian
PYTHONIOENCODING="utf-16-be" python -c 'import sys; print(sys.stdin.encoding, sys.stdout.encoding)'
utf-16-be utf-16-be
Terakhir: Anda dapat menggunakan A) atau B) atau keduanya!
sumber
from __future__ import unicode_literals
lihat diskusiDimulai dengan PyDev 3.4.1, pengkodean default tidak diubah lagi. Lihat tiket ini untuk detailnya.
Untuk versi sebelumnya, solusinya adalah memastikan PyDev tidak berjalan dengan UTF-8 sebagai pengkodean default. Di bawah Eclipse, jalankan pengaturan dialog ("jalankan konfigurasi", jika saya ingat dengan benar); Anda dapat memilih pengkodean default pada tab umum. Ubah ke US-ASCII jika Anda ingin mendapatkan kesalahan ini 'lebih awal' (dengan kata lain: di lingkungan PyDev Anda). Lihat juga entri blog asli untuk solusi ini .
sumber
Mengenai python2 (dan hanya python2), beberapa jawaban sebelumnya mengandalkan penggunaan peretasan berikut:
import sys reload(sys) # Reload is a hack sys.setdefaultencoding('UTF8')
Tidak disarankan untuk menggunakannya (periksa ini atau ini )
Dalam kasus saya, ini datang dengan efek samping: Saya menggunakan notebook ipython, dan setelah saya menjalankan kode fungsi ´print´ tidak lagi berfungsi. Saya kira akan ada solusi untuk itu, tetapi tetap saya pikir menggunakan peretasan seharusnya bukan pilihan yang tepat.
Setelah mencoba banyak opsi, salah satu yang berhasil untuk saya adalah menggunakan kode yang sama di
sitecustomize.py
, di mana potongan kode itu seharusnya berada . Setelah mengevaluasi modul itu, fungsi setdefaultencoding dihapus dari sys.Jadi solusinya adalah menambahkan ke file
/usr/lib/python2.7/sitecustomize.py
kode:import sys sys.setdefaultencoding('UTF8')
Ketika saya menggunakan virtualenvwrapper file yang saya edit adalah
~/.virtualenvs/venv-name/lib/python2.7/sitecustomize.py
.Dan ketika saya menggunakan dengan notebook python dan conda, itu benar
~/anaconda2/lib/python2.7/sitecustomize.py
sumber
Ada posting blog yang berwawasan tentang itu.
Lihat https://anonbadger.wordpress.com/2015/06/16/why-sys-setdefaultencoding-will-break-code/ .
Saya memparafrasekan isinya di bawah ini.
Dalam python 2 yang tidak diketik dengan kuat mengenai pengkodean string, Anda dapat melakukan operasi pada string yang dikodekan berbeda, dan berhasil. Misalnya, berikut ini akan kembali
True
.u'Toshio' == 'Toshio'
Itu akan berlaku untuk setiap string (normal, tidak difiksasi) yang dikodekan
sys.getdefaultencoding()
, yang menjadi defaultascii
, tetapi tidak yang lain.Pengkodean default dimaksudkan untuk diubah di seluruh sistem
site.py
, tetapi tidak di tempat lain. Peretasan (juga disajikan di sini) untuk mengaturnya dalam modul pengguna hanyalah: peretasan, bukan solusinya.Python 3 memang mengubah pengkodean sistem ke default ke utf-8 (ketika LC_CTYPE sadar-unicode), tetapi masalah mendasar diselesaikan dengan persyaratan untuk secara eksplisit menyandikan string "byte" setiap kali mereka digunakan dengan string unicode.
sumber
Pertama:
reload(sys)
dan menyetel beberapa pengkodean default acak hanya terkait kebutuhan aliran terminal keluaran adalah praktik yang buruk.reload
sering mengubah hal-hal dalam sys yang telah diterapkan tergantung pada lingkungan - misalnya aliran sys.stdin / stdout, sys.excepthook, dll.Memecahkan masalah encode di stdout
Solusi terbaik yang saya tahu untuk memecahkan masalah encode dari
print
string unicode dan di luar-asciistr
(misalnya dari literals) di sys.stdout adalah: menjaga sys.stdout (objek seperti file) yang mampu dan secara opsional toleran terhadap kebutuhan:Ketika
sys.stdout.encoding
iniNone
untuk beberapa alasan, atau non-ada, atau keliru palsu atau "kurang" dari apa yang stdout terminal atau streaming benar-benar mampu, kemudian mencoba untuk memberikan yang benar.encoding
atribut. Akhirnya dengan menggantisys.stdout & sys.stderr
dengan objek seperti file terjemahan.Ketika terminal / stream masih tidak dapat menyandikan semua karakter unicode yang terjadi, dan ketika Anda tidak ingin merusaknya
print
hanya karena itu, Anda dapat memperkenalkan perilaku encode-with-replace dalam menerjemahkan objek seperti file.Berikut contohnya:
#!/usr/bin/env python # encoding: utf-8 import sys class SmartStdout: def __init__(self, encoding=None, org_stdout=None): if org_stdout is None: org_stdout = getattr(sys.stdout, 'org_stdout', sys.stdout) self.org_stdout = org_stdout self.encoding = encoding or \ getattr(org_stdout, 'encoding', None) or 'utf-8' def write(self, s): self.org_stdout.write(s.encode(self.encoding, 'backslashreplace')) def __getattr__(self, name): return getattr(self.org_stdout, name) if __name__ == '__main__': if sys.stdout.isatty(): sys.stdout = sys.stderr = SmartStdout() us = u'aouäöüфżß²' print us sys.stdout.flush()
Menggunakan literal string biasa di luar ascii dengan kode Python 2/2 + 3
Satu-satunya alasan yang baik untuk mengubah pengkodean default global (ke UTF-8 saja) menurut saya adalah mengenai keputusan kode sumber aplikasi - dan bukan karena masalah pengkodean aliran I / O: Untuk menulis literal string ascii ke dalam kode tanpa dipaksa untuk selalu menggunakan
u'string'
pelolosan unicode gaya. Hal ini dapat dilakukan secara agak konsisten (terlepas dari apa yang anonbadger artikel ) dengan menjaga basis kode sumber Python 2 atau Python 2 + 3 yang menggunakan literal string biasa ascii atau UTF-8 secara konsisten - sejauh string tersebut berpotensi menjalani silent unicode dan berpindah antar modul atau berpotensi pergi ke stdout. Untuk itu, pilih "# encoding: utf-8
"atau ascii (tanpa deklarasi). Ubah atau jatuhkan pustaka yang masih mengandalkan dengan cara yang sangat bodoh secara fatal pada kesalahan pengkodean default ascii di luar chr # 127 (yang jarang terjadi saat ini).Dan lakukan seperti ini pada permulaan aplikasi (dan / atau melalui sitecustomize.py) selain
SmartStdout
skema di atas - tanpa menggunakanreload(sys)
:... def set_defaultencoding_globally(encoding='utf-8'): assert sys.getdefaultencoding() in ('ascii', 'mbcs', encoding) import imp _sys_org = imp.load_dynamic('_sys_org', 'sys') _sys_org.setdefaultencoding(encoding) if __name__ == '__main__': sys.stdout = sys.stderr = SmartStdout() set_defaultencoding_globally('utf-8') s = 'aouäöüфżß²' print s
Dengan cara ini string literal dan sebagian besar operasi (kecuali iterasi karakter) bekerja dengan nyaman tanpa memikirkan konversi unicode seolah-olah hanya akan ada Python3. File I / O tentu saja selalu membutuhkan perhatian khusus terkait pengkodean - seperti pada Python3.
Catatan: string dataran kemudian secara implisit diubah dari utf-8 menjadi unicode
SmartStdout
sebelum diubah menjadi enconding aliran keluaran.sumber
Berikut adalah pendekatan yang saya gunakan untuk menghasilkan kode yang kompatibel dengan python2 dan python3 dan selalu menghasilkan keluaran utf8 . Saya menemukan jawaban ini di tempat lain, tetapi saya tidak dapat mengingat sumbernya.
Pendekatan ini bekerja dengan mengganti
sys.stdout
dengan sesuatu yang tidak seperti file (tetapi masih hanya menggunakan hal-hal di pustaka standar). Ini mungkin menyebabkan masalah untuk pustaka yang mendasari Anda, tetapi dalam kasus sederhana di mana Anda memiliki kontrol yang baik atas bagaimana sys.stdout out digunakan melalui kerangka kerja Anda, ini bisa menjadi pendekatan yang masuk akal.sys.stdout = io.open(sys.stdout.fileno(), 'w', encoding='utf8')
sumber
Ini adalah peretasan cepat untuk siapa saja yang (1) Pada platform Windows (2) menjalankan Python 2.7 dan (3) kesal karena perangkat lunak yang bagus (yaitu, tidak ditulis oleh Anda sehingga tidak segera menjadi kandidat untuk pencetakan encode / decode manuver) tidak akan menampilkan "karakter unicode cantik" di lingkungan IDLE (Pythonwin mencetak unicode fine), Misalnya, simbol Logika Urutan Pertama rapi yang digunakan Stephan Boyer dalam keluaran dari penguji pedagogiknya di Penguji Logika Urutan Pertama .
Saya tidak suka gagasan memaksa sys reload dan saya tidak bisa mendapatkan sistem untuk bekerja sama dengan pengaturan variabel lingkungan seperti PYTHONIOENCODING (mencoba variabel lingkungan Windows langsung dan juga menjatuhkannya di sitecustomize.py di paket situs sebagai satu liner = 'utf-8').
Jadi, jika Anda ingin meretas jalan Anda menuju sukses, buka direktori IDLE Anda, biasanya: "C: \ Python27 \ Lib \ idlelib" Temukan file IOBinding.py. Buat salinan file itu dan simpan di tempat lain sehingga Anda dapat kembali ke perilaku asli saat Anda memilih. Buka file di idlelib dengan editor (misalnya, IDLE). Pergi ke area kode ini:
# Encoding for file names filesystemencoding = sys.getfilesystemencoding() encoding = "ascii" if sys.platform == 'win32': # On Windows, we could use "mbcs". However, to give the user # a portable encoding name, we need to find the code page try: # --> 6/5/17 hack to force IDLE to display utf-8 rather than cp1252 # --> encoding = locale.getdefaultlocale()[1] encoding = 'utf-8' codecs.lookup(encoding) except LookupError: pass
Dengan kata lain, komentari baris kode asli setelah ' coba ' yang membuat variabel pengkodean sama dengan locale.getdefaultlocale (karena itu akan memberi Anda cp1252 yang tidak Anda inginkan) dan sebagai gantinya paksa paksa ke 'utf-8 '(dengan menambahkan baris' encoding = 'utf-8 ' seperti yang ditunjukkan).
Saya percaya ini hanya mempengaruhi tampilan IDLE ke stdout dan bukan pengkodean yang digunakan untuk nama file, dll. (Yang diperoleh di filesystemencoding sebelumnya). Jika Anda memiliki masalah dengan kode lain yang Anda jalankan di IDLE nanti, cukup ganti file IOBinding.py dengan file asli yang tidak dimodifikasi.
sumber
Ini memperbaiki masalah saya.
import os os.environ["PYTHONIOENCODING"] = "utf-8"
sumber
Anda dapat mengubah pengkodean seluruh sistem operasi Anda. Di Ubuntu Anda dapat melakukan ini dengan
sudo apt install locales sudo locale-gen en_US en_US.UTF-8 sudo dpkg-reconfigure locales
sumber