Python'da açık ve codec'ler arasındaki fark.


99

Python'da bir metin dosyası açmanın iki yolu vardır:

f = open(filename)

Ve

import codecs
f = codecs.open(filename, encoding="utf-8")

Ne zaman codecs.opentercih edilir open?


46
Bir argüman kazandığından codecs.open(), bunun 3.x'te kullanılmadığına dikkat edin . open()encoding
Ignacio Vazquez-Abrams

Ayrıca 3. bir yol var (en azından Python 2.x'te): "f = dosya (dosya adı) '
Adam Parkin

1
@ IgnacioVazquez-Abrams Kullanılmayan herhangi bir bağlantı var codecs.open()mı? Bunu python3 belgelerinde düşünmüyorum: docs.python.org/3.7/library/codecs.html
varela

1
@varela: Bahsettiğiniz Python dokümantasyon sayfası şöyle diyor: "yerleşik open () ve ilişkili io modülü, kodlanmış metin dosyalarıyla çalışmak için önerilen yaklaşımdır"
Luciano Ramalho

Yanıtlar:


83

Python 2.6'dan beri , artık kullanılmayan gibi io.open()bir encodingargüman da alan iyi bir uygulama kullanmaktır codecs.open(). Python 3'te, yerleşik io.openiçin bir takma addır open(). Yani io.open()Python 2.6 ve Python 3.4 dahil tüm sonraki sürümlerinde çalışır. Dokümanlara bakın: http://docs.python.org/3.4/library/io.html

Şimdi, orijinal soru için: okurken metni size gereken Python 2'de (HTML, XML ve JSON "düz metin" dahil) her zaman kullanmak io.open()açık bir kodlamayla veya open()Python 3'te açık bir kodlamayla Aksi araçlarının doğru olsun Unicode'un kodunu çözebilir veya hemen bir hata alarak, hata ayıklamayı çok daha kolay hale getirir.

Saf ASCII "düz metin" uzak geçmişten bir efsanedir. Uygun İngilizce metinler kıvrık tırnak işaretleri, uzun tireler, madde işaretleri, € (euro işaretleri) ve hatta iki nokta (¨) kullanır. Saf olmayın! (Ve Cephe tasarım modelini de unutmayalım!)

Saf ASCII gerçek bir seçenek open()olmadığından, açık bir kodlama olmadan yalnızca ikili dosyaları okumak için kullanışlıdır .


5
@ForeverWintr Cevap orada oldukça açık: io.open()metin için ve open()sadece ikili için kullanın. Bunun anlamı, codecs.open()hiç tercih edilmemesidir.
Bdoserror

3
@Bdoserror, Açıkça bir cevap var, ama sorulan sorunun cevabı değil. Soru arasındaki fark ile ilgili olduğu openve codecs.openikincisi, birincisine tercih olduğunda spesifik olarak ve. Bahsetmek kadar fazla codecs.openolmayan bir cevap bu soruyu cevaplayamaz.
ForeverWintr

3
@ForeverWintr Eğer OP yanlış soru sorduysa (yani codecs.open()kullanımın doğru olduğu varsayımıyla ) o zaman ne zaman kullanılacağına dair "doğru" bir cevap yoktur. Cevap io.open()bunun yerine kullanmaktır . Sanki "duvara çivi çakmak için ne zaman anahtar kullanmalıyım?" Doğru cevap "çekiç kullan" dır.
Bdoserror

20

Şahsen ben her zaman kullanmak codecs.openkullanımına açık tanımlanmış bir ihtiyaç yoksa open**. Bunun nedeni, programlarıma utf-8 girdisini gizlice sokarak ısırıldığım birçok kez oldu. "Ah, bunun her zaman ascii olacağını biliyorum" sık sık bozulan bir varsayım olma eğilimindedir.

Varsayılan kodlama olarak 'utf-8'i varsaymak, deneyimlerime göre daha güvenli bir varsayılan seçimdir, çünkü ASCII UTF-8 olarak değerlendirilebilir, ancak tersi doğru değildir. Ve bu durumlarda , girdinin ASCII olduğunu gerçekten bildiğimde , o zaman hala "açık, örtükten daha iyidir"codecs.open inancına sahip olduğum gibi yapıyorum .

** - Python 2.x'te, soruya yapılan yorum Python 3'te yer openaldığındancodecs.open


gerçekten anlamadığım şey, neden openbazen unicode setinin UTF-8 kodlu latin olmayan karakterlerini çok iyi işleyebildiği ve bazen başarısız bir şekilde başarısız olduğu ...
cedbeu

Bu bana mantıklı geliyor. io.openpython
2.7.5'te

1
@radtek, bunun belgelenmemiş olduğu konusunda haklısın; ancak (en azından 2.7.12'de) io.openkabul eder encoding, newlineparametreler ve bunları Python 3'ün yaptığı gibi yorumlar. Aksine codecs.open, ( ) yazmayı denerseniz, Python 2.7'de bile açılmış bir dosya io.openyükselecektir . İle açılan bir dosya , bunun yerine örtük dönüştürmeyi deneyecek ve genellikle kafa karıştırıcı e -postalara neden olacaktır . TypeError: write() argument 1 must be unicode, not strstrbytescodecs.openunicodeUnicodeDecodeError
jochietoch

9

Python 2'de unicode dizeleri ve bytestrings vardır. Sadece bytestrings kullanırsanız, açılmış bir dosyayı open()gayet iyi okuyabilir / yazabilirsiniz . Sonuçta, dizeler yalnızca bayttır.

Sorun, örneğin bir unicode dizeniz olduğunda ve aşağıdakileri yaptığınızda ortaya çıkar:

>>> example = u'Μου αρέσει Ελληνικά'
>>> open('sample.txt', 'w').write(example)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-2: ordinal not in range(128)

Yani burada açıkçası, unicode dizenizi utf-8'de açıkça kodluyorsunuz veya bunu codecs.opensizin için şeffaf bir şekilde yapmak için kullanıyorsunuz .

Yalnızca bytestrings kullanıyorsanız, sorun yok:

>>> example = 'Μου αρέσει Ελληνικά'
>>> open('sample.txt', 'w').write(example)
>>>

Bundan daha fazla işin içine girer, çünkü bir unicode ve +operatörle bytestring dizgesini birleştirdiğinizde, bir unicode dizesi elde edersiniz. Onun tarafından ısırılması kolay.

Ayrıca codecs.openASCII olmayan karakterlerin geçtiği bytestrings'i sevmez:

codecs.open('test', 'w', encoding='utf-8').write('Μου αρέσει')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/codecs.py", line 691, in write
    return self.writer.write(data)
  File "/usr/lib/python2.7/codecs.py", line 351, in write
    data, consumed = self.encode(object, self.errors)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xce in position 0: ordinal not in range(128)

Girdi / çıktı dizgeleri hakkında tavsiye, normalde "mümkün olduğu kadar erken unicode'a ve mümkün olduğu kadar geç bytestrings'e dönme" şeklindedir. Kullanmak codecs.open, ikincisini çok kolay bir şekilde yapmanızı sağlar.

Unicode dizeleri verdiğinize dikkat edin, ASCII olmayan karakterlere sahip olabilecek testlere değil.


İkinci örneğinizi açıklayabilir misiniz? İlk örneğinizle aynı görünüyor, öyleyse sonuç neden farklı olsun?
Chris Johnson

u''İlk örnekteki kullanımına dikkat edin . Bu, bytestring değil, bir unicode dizesi oluşturduğum anlamına geliyor. Bu, iki örnek arasındaki farktır. İkinci örnekte bir bytestring oluşturuyorum ve bunlardan birini bir dosyaya yazmak gayet iyi. ASCII dışında karakterler kullanıyorsanız, bir unicode dizesi uygun değildir.
Mandible79

7

Belirli bir kodlamaya sahip bir dosyayı açmanız gerektiğinde, codecsmodülü kullanırsınız .


15
: Ben tüm metin dosyaları belirli bir kodlama, bir şekilde (sanırım
cedbeu

5

codecs.open, sanırım, Python 2yerleşik açıklığın çok daha basit bir arayüze ve daha az yeteneğe sahip olduğu günlerden kalan bir şey. Python 2'de yerleşik openkodlama argümanı almaz, bu nedenle ikili mod veya varsayılan kodlamadan başka bir şey kullanmak isterseniz codecs.open kullanılması gerekiyordu.

İçinde Python 2.6 , io modülü işleri biraz daha basit hale getirmek için yardıma geldi. Resmi belgelere göre

New in version 2.6.

The io module provides the Python interfaces to stream handling.
Under Python 2.x, this is proposed as an alternative to the
built-in file object, but in Python 3.x it is the default
interface to access files and streams.

Bunu söyledikten codecs.opensonra, mevcut senaryoda düşünebildiğim tek kullanım geriye dönük uyumluluk. Diğer tüm senaryolarda (Python <2.6 kullanmıyorsanız) kullanılması tercih edilir io.open. AyrıcaPython 3.x io.open aynıdırbuilt-in open

Not:

Arasında sözdizimsel bir fark var codecs.open veio.open .

codecs.open:

open(filename, mode='rb', encoding=None, errors='strict', buffering=1)

io.open:

open(file, mode='r', buffering=-1, encoding=None,
     errors=None, newline=None, closefd=True, opener=None)

Sadece codecs.openve io.opensöz dizimi bakımından farklılık, farklı türdeki nesneleri döndürür. Ayrıca codecs.openher zaman ikili moddaki dosyalarla çalışır.
wombatonfire

4
  • İkili dosya yüklemek istediğinizde f = io.open(filename, 'b').

  • Bir metin dosyasını açmak için her zaman f = io.open(filename, encoding='utf-8')açık kodlamayla kullanın .

Gelen piton 3 Ancak openaynı şeyi yapar io.openve bunun yerine kullanılabilir.

Not: kullanımdan kaldırılması ve python 2.6'da kullanıma sunulmasından sonra yerini alması codecs.openplanlanmaktadır . Bunu yalnızca kodun önceki python sürümleriyle uyumlu olması gerekiyorsa kullanırdım. Python'da kodekler ve unicode hakkında daha fazla bilgi için Unicode NASIL belgesine bakın .io.open


1. Neden ikili modda bir dosyayı io.openveya ile açamıyorum codecs.open? 2. codecs.openhenüz kullanımdan kaldırılmadı, bağlantı verdiğiniz sayfadaki tartışmayı okuyun.
wombatonfire

Güzel nokta! 1. İkisini de kullanabilirsiniz, ancak yine codec bileşenlerine karşı tavsiye ederim. Python 2.5 veya daha eski sürümde değilseniz açın. 2. Cevabımı, kullanımdan kaldırmanın hemen değil, gelecekte gerçekleşeceğini yansıtacak şekilde güncelledim.
wihlke

3

Metin dosyalarıyla çalışırken ve şeffaf kodlama ve Unicode nesnelerine kod çözme istediğinizde.


0

Bir .asm dosyasını açıp dosyayı işleme koyacak bir durumdaydım.

#https://docs.python.org/3/library/codecs.html#codecs.ignore_errors
#https://docs.python.org/3/library/codecs.html#codecs.Codec.encode
with codecs.open(file, encoding='cp1252', errors ='replace') as file:

Çok fazla sorun yaşamadan tüm dosyayı okuyabilirim, herhangi bir öneri?

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.