Apakah menutup file secara eksplisit penting?

149

Dalam Python, jika Anda membuka file tanpa memanggil close(), atau menutup file tetapi tidak menggunakan try- finally" with" pernyataan, apakah ini masalah? Atau apakah cukup sebagai praktik pengkodean untuk mengandalkan pengumpulan sampah Python untuk menutup semua file? Sebagai contoh, jika seseorang melakukan ini:

for line in open("filename"):
    # ... do stuff ...

... apakah ini masalah karena file tidak pernah dapat ditutup dan pengecualian dapat terjadi yang mencegahnya tidak ditutup? Atau pasti akan ditutup pada akhir forpernyataan karena file keluar dari ruang lingkup?

pengguna553702
sumber
13
File tersebut tidak keluar dari lingkup pada akhir forblok. Jumlah referensi akan menjadi nol, menyebabkannya ditutup secara otomatis, tetapi hanya fungsi, kelas, dan modul yang mendefinisikan cakupan dalam Python, bukan pernyataan majemuk lainnya.
agf
18
Itu bukan masalah kecuali itu masalah. Pada level OS, semua file yang dibuka oleh skrip akan ditutup ketika skrip keluar, jadi Anda tidak perlu khawatir tentang menutup file dalam skrip alat sekali pakai. Namun, proses memiliki batasan pada jumlah file terbuka yang dapat dipelihara, sehingga skrip yang berumur panjang atau kompleks mungkin perlu lebih hati-hati. Bagaimanapun, ini adalah kebiasaan yang baik untuk menutup file Anda.
Russell Borogove
3
@agf: Anda benar bahwa file tidak keluar dari ruang lingkup, tetapi itu tidak terkait dengan perbedaan antara forblok dan fungsi / kelas / modul. Ini jauh lebih sederhana dari itu: objek tidak memiliki cakupan, hanya nama yang melakukannya. Tidak ada nama yang merujuk ke objek ini, jadi tidak ada apa pun di sini untuk tetap berada dalam ruang lingkup atau keluar dari ruang lingkup.
maks
@ Max Komentar saya mengoreksi asumsinya bahwa ada ruang lingkup yang terkait dengan forloop, dan menyebutkan bahwa file ditutup karena alasan yang sama sekali berbeda. Itu tidak masuk ke lingkup apa yang ada di Python, karena itu tidak relevan di sini.
agf
@ Max ada referensi implisit mencakup itu untuk loop ... ini adalah argumen semantik
Peter R

Jawaban:

126

Dalam contoh Anda file tidak dijamin akan ditutup sebelum juru bahasa keluar. Dalam versi CPython saat ini, file akan ditutup pada akhir for for loop karena CPython menggunakan penghitungan referensi sebagai mekanisme pengumpulan sampah utamanya, tetapi itu adalah detail implementasi, bukan fitur bahasa. Implementasi lain dari Python tidak dijamin bekerja dengan cara ini. Misalnya IronPython, PyPy, dan Jython tidak menggunakan penghitungan referensi dan karenanya tidak akan menutup file di akhir loop.

Ini praktik yang buruk untuk mengandalkan implementasi pengumpulan sampah CPython karena membuat kode Anda kurang portabel. Anda mungkin tidak memiliki kebocoran sumber daya jika Anda menggunakan CPython, tetapi jika Anda pernah beralih ke implementasi Python yang tidak menggunakan penghitungan referensi Anda harus melalui semua kode Anda dan memastikan semua file Anda ditutup dengan benar.

Untuk contoh Anda gunakan:

with open("filename") as f:
     for line in f:
        # ... do stuff ...
Peter Graham
sumber
8
Apakah menggunakan with open() as fsecara otomatis menutup file setelah selesai?
Rohan
24
@Rohan ya, itu adalah sihir kecil yang withdisediakan oleh pernyataan itu, tetapi tentu saja agar sihir ini bekerja, objek harus memiliki metode utama __enter__dan __exit__, yang terakhir objek melakukan closedan hal-hal pembersihan lainnya yang perlu dilakukan di akhir withpernyataan ...
Copperfield
1
FYI: Jawaban ini hanya menjelaskan "kapan akan ditutup" tetapi tidak menjelaskan "bagaimana jika tetap terbuka". Untuk yang terakhir, harap baca "Apa yang akan terjadi jika file tetap terbuka?" bagian dalam jawaban ini ( askubuntu.com/questions/701491/… )
RayLuo
Selain itu, tidak menutup file dapat menyebabkan file terpotong karena konten file belum dihapus.
Erwan Legrand
Jadi jika saya tidak menutup file, apakah saya akan mendapatkan memori saya kembali setelah program berhenti berjalan? Atau apakah saya benar-benar harus keluar dari seluruh penerjemah?
Pro Q
22

Beberapa Python akan menutup file secara otomatis ketika mereka tidak lagi direferensikan, sementara yang lain tidak akan dan itu tergantung pada O / S untuk menutup file ketika interpreter Python keluar.

Bahkan untuk Python yang akan menutup file untuk Anda, waktunya tidak dijamin: itu bisa segera, atau bisa detik / menit / jam / hari kemudian.

Jadi, sementara Anda mungkin tidak mengalami masalah dengan Python yang Anda gunakan, sudah pasti bukan praktik yang baik untuk membiarkan file Anda tetap terbuka. Bahkan, di cpython 3 Anda sekarang akan mendapatkan peringatan bahwa sistem harus menutup file untuk Anda jika Anda tidak melakukannya.

Moral: Bersihkan dirimu. :)

Ethan Furman
sumber
9
File ditutup ketika mereka tidak lagi dirujuk dalam CPython, tapi itu bukan fitur bahasa. Jika itu Anda bisa dengan senang hati mengandalkannya.
Peter Graham
9

Meskipun cukup aman untuk menggunakan konstruksi seperti itu dalam kasus khusus ini, ada beberapa peringatan untuk generalisasi praktik seperti itu:

  • run berpotensi kehabisan deskriptor file, meskipun tidak mungkin, bayangkan berburu bug seperti itu
  • Anda mungkin tidak dapat menghapus file tersebut pada beberapa sistem, misalnya win32
  • jika Anda menjalankan sesuatu selain CPython, Anda tidak tahu kapan file ditutup untuk Anda
  • jika Anda membuka file dalam mode tulis atau baca-tulis, Anda tidak tahu kapan data dibilas
Dima Tisnek
sumber
3

File tidak mendapatkan sampah yang dikumpulkan, dan karenanya ditutup. GC menentukan kapan ditutup, bukan Anda. Jelas, ini bukan praktik yang disarankan karena Anda mungkin menekan batas pegangan file terbuka jika Anda tidak menutup file segera setelah Anda selesai menggunakannya. Bagaimana jika dalam forlingkaran Anda, Anda membuka lebih banyak file dan membiarkannya tetap?

Nam Nguyen
sumber
Tetapi jika Anda membuka file lain dalam loop itu, masih akan ada lebih dari satu file yang dibuka secara bersamaan apakah Anda secara eksplisit menutup salah satu dari mereka atau tidak. Apakah Anda mengatakan bahwa file tersebut tidak harus dikumpulkan dengan sampah segera setelah file keluar dari cakupan, sehingga akan ditutup lebih cepat jika dilakukan secara eksplisit? Bagaimana dengan ketika pengecualian terjadi (ketika Anda menggunakan dengan / coba-akhirnya vs tidak melakukannya)?
user553702
1
Di CPython, penghitungan referensi akan membuatnya dikumpulkan setelah forpernyataan - Anda tidak perlu menunggu untuk menjalankan pengumpulan sampah berikutnya.
agf
3

Hai Sangat penting untuk menutup deskriptor file Anda dalam situasi ketika Anda akan menggunakan konten itu dalam skrip python yang sama. Saya hari ini sendiri menyadari setelah debugging begitu lama. Alasannya adalah konten akan diedit / dihapus / disimpan hanya setelah Anda menutup Anda deskriptor file dan perubahan terpengaruh ke file!

Jadi misalkan Anda memiliki situasi ketika Anda menulis konten ke file baru dan kemudian tanpa menutup fd Anda menggunakan file itu (bukan fd) dalam perintah shell lain yang membaca kontennya. Dalam situasi ini Anda tidak akan mendapatkan konten untuk perintah shell seperti yang diharapkan dan jika Anda mencoba untuk debug Anda tidak dapat menemukan bug dengan mudah. Anda juga dapat membaca lebih lanjut di entri blog saya http://magnificentzps.blogspot.in/2014/04/importance-of-closing-file-descriptor.html

Zeel Shah
sumber
1

Selama proses I / O, data di-buffer: ini berarti disimpan di lokasi sementara sebelum ditulis ke file.

Python tidak menyiram buffer — yaitu, menulis data ke file — hingga yakin Anda selesai menulis. Salah satu cara untuk melakukan ini adalah dengan menutup file.

Jika Anda menulis ke file tanpa menutup, data tidak akan membuatnya ke file target.

Sanket Nagrale
sumber