Menutup berkas secara manual dengan close() tampak mudah dalam contoh pendek, tetapi rapuh dalam program nyata. Begitu exception, return, atau break memutus alur di antara open() dan close(), pemanggilan close() terlewati dan berkas tetap menggantung terbuka — lengkap dengan data yang belum ter-flush dan file descriptor yang bocor. Statement with hadir untuk menghilangkan kelas bug ini sekaligus, dan kebetulannya pola yang sama juga dipakai banyak resource lain di luar berkas.
Bentuk Dasar with open(…) #
Statement with membuka berkas, menjalankan blok, lalu menutup berkas otomatis tepat saat blok berakhir:
with open("pidato.txt", "w", encoding="utf-8") as berkas:
berkas.write("Baris pertama ditulis di dalam blok with.\n")
print("Di dalam blok, berkas.closed =", berkas.closed)
print("Di luar blok, berkas.closed =", berkas.closed)
print(open("pidato.txt", encoding="utf-8").read(), end="")Output yang Dihasilkan:
Di dalam blok, berkas.closed = False
Di luar blok, berkas.closed = True
Baris pertama ditulis di dalam blok with.Mari kita amati mekanismenya:
- Baris 1 (
with open(...) as berkas:): fungsiopen()membuka berkas, lalu object file diikat ke variabelberkashanya untuk durasi blok. - Baris 2-3: method
write()bekerja normal; atributclosedmasihFalsekarena kita masih di dalam blok. - Baris 5-6: begitu blok berakhir, interpreter Python menutup berkas tanpa kita minta — atribut
closedbernilaiTrue, dan pembacaan ulang membuktikan datanya sudah masuk ke disk.
Di balik layar, object file mengimplementasikan context manager protocol: method __enter__() dipanggil saat blok dimulai, dan method __exit__() dipanggil saat blok berakhir dalam kondisi apa pun. Membuat context manager sendiri membutuhkan materi class pada section Object-Oriented Programming. Untuk sekarang, cukup tahu bahwa with tidak eksklusif milik berkas — object seperti TemporaryDirectory() pada Chapter Temporary Files dan berbagai kunci sinkronisasi juga dibuka dengan pola yang sama persis.
Penutupan Terjamin Bahkan Saat Exception #
Klaim “with selalu menutup berkas” mudah dibuktikan. Program berikut sengaja memicu ValueError di tengah blok with:
try:
with open("hasil.txt", "w", encoding="utf-8") as berkas:
berkas.write("Bagian ini sudah masuk ke disk.\n")
angka = int("bukan angka")
except ValueError:
print("ValueError tertangkap")
print("berkas.closed =", berkas.closed)
print(open("hasil.txt", encoding="utf-8").read(), end="")Output yang Dihasilkan:
ValueError tertangkap
berkas.closed = True
Bagian ini sudah masuk ke disk.Urutan kejadiannya begini:
- Baris 2 (
with open(...)): berkashasil.txtdibuka dengan mode tulis. - Baris 3 (
berkas.write(...)): satu baris masuk ke buffer lalu ke disk. - Baris 4 (
angka = int("bukan angka")): konversi gagal danValueErrorterlempar — blokwithberakhir secara tidak normal. - Sebelum exception diteruskan ke
except, interpreter memanggil__exit__()milik object file, yang menutup berkas dan meng-flush data. - Baris 8-9: penangan exception berjalan, dan dua baris terakhir membuktikan
berkas.closedbernilaiTrueserta data sebelum exception selamat.
Bandingkan dengan pola manual: tanpa with, exception pada baris keempat membuat close() tidak pernah terpanggil, data berpotensi hilang, dan file descriptor bocor. Penanganan exception sendiri telah dibahas pada Chapter try dan except.
Membuka Beberapa Berkas Sekaligus #
Kebutuhan membaca satu berkas sambil menulis berkas lain sangat umum, misalnya menyalin isi dengan transformasi ringan. Bentuk pertama adalah with bersarang — blok berikut menyiapkan sumber.txt terlebih dahulu, lalu menyalinnya baris demi baris:
with open("sumber.txt", "w", encoding="utf-8") as berkas:
berkas.write("Budi Santoso\nSiti Nurhaliza\nJoko Anwar\n")
with open("sumber.txt", encoding="utf-8") as sumber:
with open("salinan.txt", "w", encoding="utf-8") as tujuan:
for baris in sumber:
tujuan.write(baris)
print(open("salinan.txt", encoding="utf-8").read(), end="")Output yang Dihasilkan:
Budi Santoso
Siti Nurhaliza
Joko AnwarIndentasi bertingkat seperti ini cepat melebar. Python mengizinkan beberapa context manager dalam satu baris dengan tanda koma — blok berikut memakai sumber.txt yang barusan dibuat — dan bentuk inilah yang menjadi standar:
with open("sumber.txt", encoding="utf-8") as sumber, open("salinan.txt", "w", encoding="utf-8") as tujuan:
for baris in sumber:
tujuan.write(baris)
print(open("salinan.txt", encoding="utf-8").read(), end="")Output yang Dihasilkan:
Budi Santoso
Siti Nurhaliza
Joko Anwar