Perbedaan antara open dan codecs.open dengan Python


98

Ada dua cara untuk membuka file teks dengan Python:

f = open(filename)

Dan

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

Kapan codecs.openlebih disukai open?


46
Perhatikan bahwa codecs.open()dalam 3.x sudah usang, karena open()mendapatkan encodingargumen.
Ignacio Vazquez-Abrams

Ada juga cara ke-3 (setidaknya dalam Python 2.x): `f = file (nama file) '
Adam Parkin

1
@ IgnacioVazquez-Abrams Apakah ada link yang codecs.open()sudah usang? Saya tidak berpikir ini di dokumen python3
varela

1
@ varela: halaman dokumentasi Python yang Anda sebutkan mengatakan: "builtin open () dan modul io terkait adalah pendekatan yang direkomendasikan untuk bekerja dengan file teks yang disandikan"
Luciano Ramalho

Jawaban:


83

Sejak Python 2.6, praktik yang baik adalah menggunakan io.open() , yang juga membutuhkan encodingargumen, seperti yang sekarang sudah usang codecs.open(). Di Python 3, io.openadalah alias untuk bawaan open(). Jadi io.open()bekerja dengan Python 2.6 dan semua versi yang lebih baru, termasuk Python 3.4. Lihat dokumen: http://docs.python.org/3.4/library/io.html

Sekarang, untuk pertanyaan awal: saat membaca teks (termasuk "teks biasa", HTML, XML dan JSON) di Python 2 Anda harus selalu menggunakan io.open()dengan pengkodean eksplisit, atau open()dengan pengkodean eksplisit di Python 3. Melakukan itu berarti Anda mendapatkan dengan benar mendekode Unicode, atau langsung mendapatkan kesalahan, membuatnya lebih mudah untuk di-debug.

"Teks biasa" ASCII murni adalah mitos dari masa lalu. Teks bahasa Inggris yang tepat menggunakan tanda kutip keriting, tanda pisah em, peluru, € (tanda euro) dan bahkan diaeresis (¨). Jangan naif! (Dan jangan lupakan pola desain Façade!)

Karena ASCII murni bukanlah pilihan nyata, open()tanpa pengkodean eksplisit hanya berguna untuk membaca file biner .


5
@ForeverWintr Jawabannya cukup jelas di sana: gunakan io.open()untuk teks, dan open()hanya untuk biner. Implikasinya adalah hal codecs.open()itu sama sekali tidak disukai.
Bdoserror

2
@Bdoserror, Ada sebuah jawaban di sana, jelas, tapi itu bukan jawaban untuk pertanyaan yang diminta. Pertanyaannya adalah tentang perbedaan antara opendan codecs.open, dan secara khusus kapan yang terakhir lebih disukai daripada yang pertama. Sebuah jawaban yang tidak terlalu disebutkan codecs.opentidak dapat menjawab pertanyaan itu.
ForeverWintr

3
@ForeverWintr Jika OP menanyakan pertanyaan yang salah (yaitu dengan asumsi yang codecs.open()benar untuk digunakan) maka tidak ada jawaban yang "benar" tentang kapan harus menggunakannya. Jawabannya adalah dengan menggunakan io.open(). Ini seperti jika saya bertanya "kapan saya harus menggunakan kunci inggris untuk menancapkan paku ke dinding?". Jawaban yang benar adalah "gunakan palu".
Bdoserror

20

Secara pribadi, saya selalu menggunakan codecs.openkecuali ada kebutuhan teridentifikasi yang jelas untuk digunakan open**. Alasannya adalah bahwa saya sering digigit karena input utf-8 menyelinap ke dalam program saya. "Oh, saya hanya tahu itu akan selalu ascii" cenderung menjadi asumsi yang sering rusak.

Dengan asumsi 'utf-8' sebagai pengkodean default cenderung menjadi pilihan default yang lebih aman menurut pengalaman saya, karena ASCII dapat diperlakukan sebagai UTF-8, tetapi kebalikannya tidak benar. Dan dalam kasus-kasus ketika saya benar-benar tahu bahwa inputnya adalah ASCII, maka saya masih melakukan codecs.openkarena saya sangat percaya pada "eksplisit lebih baik daripada implisit" .

** - dengan Python 2.x, karena komentar pada pertanyaan yang dinyatakan dengan Python 3 openmenggantikancodecs.open


apa yang saya tidak benar-benar mengerti adalah mengapa openkadang - kadang dapat menangani dengan baik karakter non-latin yang dikodekan UTF-8 dari set unicode, dan terkadang gagal total ...
cedbeu

Ini masuk akal bagi saya. io.opentidak mengambil parameter pengkodean dari apa yang saya lihat di python 2.7.5
radtek

1
@radtek, Anda benar bahwa ini tidak berdokumen; namun (setidaknya di 2.7.12) io.openmenerima encodingdan newlineparameter dan menafsirkannya seperti yang dilakukan Python 3. Tidak seperti codecs.open, file yang dibuka dengan io.openakan memunculkan TypeError: write() argument 1 must be unicode, not strbahkan dengan Python 2.7 jika Anda mencoba untuk menulis str( bytes) padanya. File yang dibuka dengan codecs.opensebaliknya akan mencoba konversi implisit ke unicode, yang sering kali menyebabkan kebingungan UnicodeDecodeError.
jochietoch

9

Di Python 2 ada string unicode dan bytestrings. Jika Anda hanya menggunakan bytestrings, Anda dapat membaca / menulis ke file yang dibuka dengan open()baik. Bagaimanapun, string hanyalah byte.

Masalahnya muncul ketika, katakanlah, Anda memiliki string unicode dan Anda melakukan hal berikut:

>>> 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)

Jadi di sini jelas Anda secara eksplisit menyandikan string unicode Anda di utf-8 atau Anda gunakan codecs.openuntuk melakukannya untuk Anda secara transparan.

Jika Anda hanya pernah menggunakan bytestrings maka tidak ada masalah:

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

Ini menjadi lebih terlibat daripada ini karena ketika Anda menggabungkan string unicode dan bytestring dengan +operator, Anda mendapatkan string unicode. Mudah digigit oleh yang satu itu.

Juga codecs.opentidak suka bytestring dengan karakter non-ASCII yang diteruskan:

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)

Saran tentang string untuk input / output biasanya "diubah ke unicode sedini mungkin dan kembali ke bytestring selambat mungkin". Menggunakan codecs.openmemungkinkan Anda melakukan yang terakhir dengan sangat mudah.

Berhati-hatilah karena Anda memberikan string unicode dan bukan bytestring yang mungkin memiliki karakter non-ASCII.


Bisakah Anda menjelaskan contoh kedua Anda? Tampaknya identik dengan contoh pertama Anda, jadi mengapa hasilnya berbeda?
Chris Johnson

Perhatikan penggunaan u''di contoh pertama. Ini berarti saya membuat string unicode, bukan bytestring. Inilah perbedaan antara kedua contoh tersebut. Pada contoh kedua saya membuat bytestring dan menulis salah satunya ke file sudah cukup. String unicode tidak baik jika Anda menggunakan karakter di luar ASCII.
Mandibula79

7

Saat Anda perlu membuka file yang memiliki pengkodean tertentu, Anda akan menggunakan codecsmodul.


15
Saya kira semua file teks memiliki pengkodean tertentu, entah bagaimana (:
cedbeu

5

codecs.open, saya kira, hanyalah sisa dari Python 2hari - hari ketika open-in open memiliki antarmuka yang jauh lebih sederhana dan kemampuan yang lebih sedikit. Di Python 2, built-in opentidak mengambil argumen encoding, jadi jika Anda ingin menggunakan sesuatu selain mode biner atau encoding default, codecs.open seharusnya digunakan.

Masuk Python 2.6, modul io membantu untuk membuat segalanya lebih sederhana. Menurut dokumentasi resmi

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.

Karena itu, satu-satunya penggunaan yang dapat saya pikirkan codecs.opendalam skenario saat ini adalah untuk kompatibilitas ke belakang. Dalam semua skenario lain (kecuali Anda menggunakan Python <2.6) lebih baik digunakan io.open. Juga di Python 3.x io.opensama denganbuilt-in open

catatan:

Ada perbedaan sintaksis antara codecs.opendan io.openjuga.

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)

Tidak hanya codecs.opendan io.openberbeda dalam hal sintaks, mereka mengembalikan objek dari tipe yang berbeda. Juga codecs.openselalu bekerja dengan file dalam mode biner.
wombatonfire

4
  • Saat Anda ingin memuat file biner, gunakan f = io.open(filename, 'b').

  • Untuk membuka file teks, selalu gunakan f = io.open(filename, encoding='utf-8')dengan encoding eksplisit.

Dalam python 3 namun openmelakukan hal yang sama seperti io.opendan dapat digunakan sebagai pengganti.

Catatan: codecs.open direncanakan untuk ditinggalkan dan diganti io.opensetelah diperkenalkan di python 2.6 . Saya hanya akan menggunakannya jika kode harus kompatibel dengan versi python sebelumnya. Untuk informasi lebih lanjut tentang codec dan unicode dengan python, lihat Unicode HOWTO .


1. Mengapa saya tidak dapat membuka file dalam mode biner dengan io.openatau codecs.open? 2. codecs.openbelum usang, baca diskusi di halaman yang Anda tautkan.
wombatonfire

Poin bagus! 1. Anda dapat menggunakan keduanya, tetapi saya akan menyarankan sekali lagi untuk menentang codecs.open kecuali Anda menggunakan python 2.5 atau yang lebih lama. 2. Saya memperbarui jawaban saya untuk mencerminkan bahwa penghentian tidak segera terjadi, melainkan di masa mendatang.
wihlke

3

Saat Anda bekerja dengan file teks dan ingin encoding dan decoding transparan menjadi objek Unicode.


0

Saya berada dalam situasi untuk membuka file .asm dan memproses file.

#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:

Tanpa banyak masalah saya bisa membaca seluruh file, ada saran?

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.