Python'un varsayılan kodlamasını değiştiriyor musunuz?


143

Ben "kodlamak olamaz" ve sorunlarını "çözmek olamaz" çok var Python ben konsoldan benim uygulamaları çalıştırdığınızda. Ancak Eclipse PyDev IDE'de varsayılan karakter kodlaması UTF-8 olarak ayarlanmış ve ben iyiyim.

Varsayılan kodlamayı ayarlamak için araştırdım ve insanlar Python'un sys.setdefaultencodingbaşlangıçta işlevi sildiğini ve kullanamadığımızı söylüyorlar.

Peki bunun için en iyi çözüm nedir?


1
The Illusive setdefaultencoding adlı blog gönderisine bakın .
djc

3
The best solution is to learn to use encode and decode correctly instead of using hacks.Bu, python2 ile her zaman bunu yapmak / sürekli olarak kendi arayüzünüzü kullanarak hatırlamak pahasına mümkün oldu . Deneyimlerim, hem python2 hem de python3 ile çalışmak istediğiniz kodu yazarken bunun son derece sorunlu hale geldiğini göstermektedir.
Att Righ

Yanıtlar:


159

İşte size setdefaultencoding()silinen işlevi geri veren daha basit bir yöntem (hack) sys:

import sys
# sys.setdefaultencoding() does not exist, here!
reload(sys)  # Reload does the trick!
sys.setdefaultencoding('UTF8')

(3.4+ Python için Not: reload()içindedir importlibkütüphanede.)

Bu yapılacak güvenli bir şey değil : Python başladığından sys.setdefaultencoding()bilerek kaldırıldığı için bu kesinlikle bir hack sys. Yeniden etkinleştirmek ve varsayılan kodlamayı değiştirmek, varsayılan olarak ASCII'ye dayanan kodu kırabilir (bu kod, genellikle düzeltmeyi imkansız veya tehlikeli hale getirecek üçüncü taraf olabilir).


5
Bu cevabı indirdim, çünkü bu cevap mevcut uygulamaları çalıştırmaya yardımcı olmuyor (soruyu yorumlamanın bir yolu olan), bir uygulamayı yazarken / korurken yanlış ve kütüphane yazarken tehlikeli. Doğru yol ayarlamaktır LC_CTYPE(veya bir uygulamada, doğru ayarlanıp ayarlanmadığını kontrol edin ve anlamlı bir hata mesajıyla iptal edin).
ibotty

@ibotty Bu cevabın bir saldırı olduğunu ve kullanmanın tehlikeli olduğunu kabul ediyorum. Yine de soruyu cevaplıyor ("Python'un varsayılan kodlaması değiştiriliyor mu?"). LC_CTYPE ortam değişkeninin Python yorumlayıcısı üzerindeki etkisi hakkında bir referansınız var mı?
Eric O Lebigot

Peki, bahsetmedi, ilk başta bir hack. bunun dışında, olduklarından bahsetmeyen tehlikeli cevaplar yardımcı olmaz.
ibotty

1
@EOL haklısın. Yine de tercih LC_CTYPE=C python -c 'import locale; print( locale.getpreferredencoding())'
kodlamasını

1
@ user2394901 sys.setdefaultencoding () kullanımı her zaman önerilmez. Ve py3k kodlaması "utf-8" ile kablolanmıştır ve değiştirilmesi bir hataya neden olur.
Marlon Abeykoon

70

Komut dosyanızın çıkışını oluşturmaya / yönlendirmeye çalıştığınızda bu hatayı alırsanız

UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)

Sadece konsolda PYTHONIOENCODING dışa aktarın ve kodunuzu çalıştırın.

export PYTHONIOENCODING=utf8


3
Benim için fark yaratan tek çözüm bu. - Bozuk yerel ayarlarla Debian 7'deyim. Teşekkürler.
Pryo

4
LC_CTYPEBunun yerine mantıklı bir şeye ayarlayın . Diğer tüm programları da mutlu eder.
ibotty

5
Python3'te daha büyük bir hata var, bu PYTHONIOENCODING=utf8varsayılan değil. Bu komut dosyalarının kırılmasını sağlarLC_ALL=C
Tino

Set LC_CTYPE to something sensible insteadBu makul bir öneri. Başka bir kişinin sisteminde çalışan kodu dağıtmaya çalıştığınızda bu çok işe yaramaz .
Att Righ

Debian ve Redhat OS'leri C.utf8daha mantıklı bir C. sağlamak için bir yerel ayar kullanır.
Arthur2e5

52

A) sys.getdefaultencoding()Çıkışı kontrol etmek için :

python -c 'import sys; print(sys.getdefaultencoding())'

ascii

Sonra

echo "import sys; sys.setdefaultencoding('utf-16-be')" > sitecustomize.py

ve

PYTHONPATH=".:$PYTHONPATH" python -c 'import sys; print(sys.getdefaultencoding())'

utf-16-be

Sitecustomize.py sayfanızı daha yüksek bir değere koyabilirsiniz PYTHONPATH.

Ayrıca reload(sys).setdefaultencoding@EOL tarafından denemek isteyebilirsiniz

B) kontrol etmek stdin.encodingve stdout.encodingsete istiyorum PYTHONIOENCODING:

python -c 'import sys; print(sys.stdin.encoding, sys.stdout.encoding)'

ascii ascii

Sonra

PYTHONIOENCODING="utf-16-be" python -c 'import sys; 
print(sys.stdin.encoding, sys.stdout.encoding)'

utf-16-be utf-16-be

Son olarak: Eğer kullanabilirsiniz A) veya B) veya her ikisi!


(python2 için) ayrı ama ilginç yukarıda uzanan from __future__ import unicode_literalsbakınız tartışmaya
lukmdo

17

PyDev 3.4.1 ile başlayarak , varsayılan kodlama artık değiştirilmiyor. Ayrıntılar için bu bilete bakın.

Önceki sürümlerde bir çözüm, PyDev'in varsayılan kodlama olarak UTF-8 ile çalışmadığından emin olmaktır. Eclipse altında, iletişim kutusu ayarlarını çalıştırın (doğru hatırlıyorsam "yapılandırmaları çalıştır"); ortak sekmede varsayılan kodlamayı seçebilirsiniz. Bu hataları 'erken' yapmak istiyorsanız bunu US-ASCII olarak değiştirin (başka bir deyişle: PyDev ortamınızda). Ayrıca bu geçici çözüm için orijinal bir blog yayınına bakın .


1
Teşekkürler Chris. Özellikle Mark T'nin yukarıdaki yorumu dikkate alındığında, cevabınız benim için en uygun gibi görünüyor. Ve öncelikle Eclipse / PyDev kullanıcısı olmayan biri için, bunu asla kendi başıma çözemezdim.
Sean

Bunu küresel olarak değiştirmek istiyorum (çalıştırma yapılandırması başına bir kez değil), ancak nasıl olduğunu anlayamadım - ayrı bir q sordunuz: stackoverflow.com/questions/9394277/…
Tim Diggins

13

Python2 (ve yalnızca python2) ile ilgili olarak, önceki cevapların bazıları aşağıdaki hack kullanımına dayanır:

import sys
reload(sys)  # Reload is a hack
sys.setdefaultencoding('UTF8')

Kullanmak için cesaretiniz kırıldı ( bunu veya bunu kontrol edin )

Benim durumumda, bir yan etkisi ile geliyor: ipython defterleri kullanıyorum ve kodu çalıştırdığımda ´print´ işlevi artık çalışmıyor. Sanırım buna bir çözüm olurdu, ama yine de kesmek kullanmanın doğru seçenek olmaması gerektiğini düşünüyorum.

Birçok seçeneği denedikten sonra, benim için çalışan , kodun olması gerektiği yerde aynı kodu kullanmaktısitecustomize.py . Bu modül değerlendirildikten sonra, setdefaultencoding işlevi sistemden kaldırılır.

Yani çözüm /usr/lib/python2.7/sitecustomize.pykodu dosyaya eklemek için :

import sys
sys.setdefaultencoding('UTF8')

Virtualenvwrapper'ı kullandığımda düzenlediğim dosya ~/.virtualenvs/venv-name/lib/python2.7/sitecustomize.py.

Ve python defterleri ve conda ile kullandığımda, ~/anaconda2/lib/python2.7/sitecustomize.py


8

Bu konuda anlayışlı bir blog yazısı var.

Bkz. Https://anonbadger.wordpress.com/2015/06/16/why-sys-setdefaultencoding-will-break-code/ .

İçeriğini aşağıda yorumluyorum.

Dizelerin kodlanması ile ilgili olarak güçlü bir şekilde yazılmayan python 2'de farklı kodlanmış dizelerde işlemler gerçekleştirebilir ve başarılı olabilirsiniz. Örneğin, aşağıdaki dönecekti True.

u'Toshio' == 'Toshio'

Bu, kodlanan sys.getdefaultencoding(), varsayılan olan asciiancak diğerlerinin değil her (normal, ön düzeltilmemiş) dize için geçerlidir .

Varsayılan kodlamanın sistem genelinde değiştirilmesi gerekiyordu site.py, ancak başka bir yerde değiştirilmeyecekti. Kullanıcı modüllerine yerleştirmek için hack'ler (burada da sunulmaktadır) sadece çözümdü: hackler, çözüm değil.

Python 3, sistem kodlamasını varsayılan olarak utf-8 olarak değiştirdi (LC_CTYPE unicode uyumlu olduğunda), ancak temel sorun, unicode dizelerle birlikte kullanıldıklarında "bayt" dizelerini açıkça kodlama gereksinimi ile çözüldü.


4

Birincisi: reload(sys)ve sadece bir çıkış terminali akışı ihtiyacı ile ilgili bazı rastgele varsayılan kodlamaların yapılması kötü bir uygulamadır. reloadgenellikle çevreye bağlı olarak yerleştirilen sys öğelerini değiştirir - örneğin sys.stdin / stdout akışları, sys.excepthook, vb.

Stdout'ta kodlama problemini çözme

printSys.stdout str' unicode dizeleri ve ötesinde ascii ' s (örneğin değişmez) gelen kodlama sorunu çözmek için bildiğim en iyi çözüm : yetenekli ve sys.stdout (dosya benzeri bir nesne) dikkat etmektir ihtiyaca göre toleranslı:

  • Ne zaman sys.stdout.encodingolduğunu Nonenedense veya mevcut olmayan ya da hatalı yanlış veya neler yapabileceğini stdout'u terminali ya gerçekten akışı daha "az" o zaman doğru sağlamaya çalışıyoruz .encodingniteliği. Sonunda sys.stdout & sys.stderr, çeviri yapan dosya benzeri bir nesne ile değiştirerek.

  • Terminal / akış hala var olan tüm unicode karakterleri kodlayamadığında ve printsadece bu nedenle kırılmak istemediğinizde , çeviri dosyası benzeri nesnede değiştirilen bir kodla davranışı ekleyebilirsiniz.

İşte bir örnek:

#!/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()

Python 2/2 + 3 kodunda ascii düz dize değişmezlerini kullanma

Küresel varsayılan kodlama değiştirmek için tek iyi neden (sadece UTF-8 için) Ben bir uygulama kaynak kodu kararı ile ilgili olduğunu düşünüyorum - I / O akışı kodlama sorunları nedeniyle değil: zorla olmadan ascii dize değişmezleri koda kod yazmak için her zaman u'string'unicode kaçış tarzı kullanmak için . Bu, ascii veya UTF-8 düz dize değişmez değerlerini sürekli olarak kullanan bir Python 2 veya Python 2 + 3 kaynak kodu temeline dikkat ederek tutarlı bir şekilde ( anonbadger'ın makalesine rağmen ) yapılabilir. Unicode dönüştürme ve modüller arasında hareket veya potansiyel olarak stdout gidin. Bunun için "# encoding: utf-8"veya ascii (bildirim yok). chr # 127 (bugün nadir olan) ötesinde ascii varsayılan kodlama hatalarına hala çok aptalca bir şekilde dayanan kütüphaneleri değiştirin veya bırakın.

Ve SmartStdoutyukarıdaki şemaya ek olarak uygulama başlangıcında (ve / veya sitecustomize.py aracılığıyla) bunu kullanmadan yapın reload(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

Bu şekilde dize değişmezleri ve çoğu işlem (karakter yineleme hariç), yalnızca Python3 gibi, unicode dönüşümü hakkında düşünmeden rahat çalışır. Dosya I / O, elbette Python3'te olduğu gibi kodlamalar konusunda her zaman özel bakıma ihtiyaç duyar.

Not: ovalar dizeleri daha sonra SmartStdoutçıkış akımının muhafazasına dönüştürülmeden önce utf-8'den unicode'a dönüştürülür.


4

Burada hem uyumlu idi üretim koduna kullanılan yaklaşım I python2 ve python3 ve her zaman üretilen utf8 çıktı. Bu cevabı başka bir yerde buldum, ama kaynağını hatırlayamıyorum.

Bu yaklaşım , oldukça dosya benzeri olmayan birsys.stdout şeyle değiştirerek çalışır (ancak yine de yalnızca standart kitaplıkta bulunan şeyleri kullanır). Bu, temeldeki kitaplıklarınız için sorunlara neden olabilir, ancak sys.stdout'un çerçeveniz üzerinden nasıl kullanıldığını iyi kontrol ettiğiniz basit bir durumda bu makul bir yaklaşım olabilir.

sys.stdout = io.open(sys.stdout.fileno(), 'w', encoding='utf8')

3

Bu benim için sorunu düzeltti.

import os
os.environ["PYTHONIOENCODING"] = "utf-8"

1

Bu, (1) Python 2.7 ve (3) çalıştıran bir Windows platformunda (2) rahatsız olan herkes için hızlı bir saldırıdır, çünkü güzel bir yazılım parçası (yani, sizin tarafınızdan yazılmadığı için kodlama / kod çözme baskısı için hemen aday olmaz) manevralar) IDLE ortamında "oldukça unicode karakterleri" göstermez (Pythonwin unicode para cezası yazdırır), örneğin, Stephan Boyer'ın First Order Logic Prover'daki pedagojik prover'ının çıkışında kullandığı düzgün First Order Logic sembolleri .

Ben bir sys yeniden yükleme zorlama fikrini beğenmedi ve sistem PYTHONIOENCODING (doğrudan Windows ortam değişkenini denedim ve aynı zamanda bir sitecustomize.py içinde site paketleri bir olarak bırakarak gibi ortam değişkenleri ayarlama ile işbirliği alamadım liner = 'utf-8').

Bu nedenle, başarıya giden yolu kesmek istiyorsanız, genellikle IDLE dizininize gidin: "C: \ Python27 \ Lib \ idlelib" IOBinding.py dosyasını bulun. Bu dosyanın bir kopyasını oluşturun ve başka bir yerde saklayın, böylece seçtiğinizde orijinal davranışa geri dönebilirsiniz. Dosyayı bir düzenleyiciyle (örn., IDLE) boş dosyada açın. Bu kod alanına gidin:

# 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

Başka bir deyişle, kodlama değişkenini locale.getdefaultlocale değerine eşit yapan ' try ' komutunu izleyen orijinal kod satırını yorumlayın (çünkü bu size istemediğiniz cp1252'yi verecektir) ve bunun yerine kaba 'utf-8' e zorlayın '( gösterildiği gibi ' encoding = 'utf-8 ' satırını ekleyerek ).

Bu sadece IDLE ekran stdout etkiler ve dosya adları vb için kullanılan kodlama (önceki dosya sistemi kodlamada elde edilen) etkilediğini düşünüyorum. IDLE içinde daha sonra çalıştırdığınız başka bir kodla ilgili bir sorununuz varsa, IOBinding.py dosyasını değiştirilmemiş orijinal dosyayla değiştirin.


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.