Menggunakan pernyataan python "with" dengan blok try-kecuali

96

Apakah ini cara yang benar untuk menggunakan pernyataan python "dengan" dalam kombinasi dengan blok coba-kecuali ?:

try:
    with open("file", "r") as f:
        line = f.readline()
except IOError:
    <whatever>

Jika ya, pertimbangkan cara lama dalam melakukan sesuatu:

try:
    f = open("file", "r")
    line = f.readline()
except IOError:
    <whatever>
finally:
    f.close()

Apakah manfaat utama dari pernyataan "dengan" di sini adalah kita dapat menghilangkan tiga baris kode? Tampaknya tidak terlalu memaksa bagi saya untuk kasus penggunaan ini (meskipun saya memahami bahwa pernyataan "dengan" memiliki kegunaan lain).

EDIT: Apakah fungsi dari dua blok kode di atas identik?

EDIT2: Beberapa jawaban pertama berbicara secara umum tentang manfaat menggunakan "dengan", tetapi tampaknya manfaat marjinal di sini. Kita semua telah (atau seharusnya) secara eksplisit memanggil f.close () selama bertahun-tahun. Saya kira satu keuntungan adalah bahwa pembuat kode ceroboh akan mendapatkan keuntungan dari penggunaan "dengan".

gaefan
sumber
Bagi saya, tidak harus mengingat untuk menutup () hal-hal di pernyataan akhirnya adalah alasan yang cukup baik untuk menggunakan 'with'. Saya telah melihat banyak kode gagal menutup sumber dayanya. Dan 'dengan' sejauh yang saya bisa lihat tidak memiliki kekurangan.
Raúl Salinas-Monteagudo

Jawaban:

140
  1. Dua blok kode yang Anda berikan bukanlah setara
  2. Kode yang Anda gambarkan sebagai cara lama dalam melakukan sesuatu memiliki bug yang serius: jika membuka file gagal, Anda akan mendapatkan pengecualian kedua dalam finallyklausa karena ftidak terikat.

Kode gaya lama yang setara adalah:

try:
    f = open("file", "r")
    try:
        line = f.readline()
    finally:
        f.close()
except IOError:
    <whatever>

Seperti yang Anda lihat, withpernyataan tersebut dapat mengurangi kerentanan terhadap kesalahan. Di versi Python yang lebih baru (2.7, 3.1), Anda juga dapat menggabungkan beberapa ekspresi dalam satu withpernyataan. Sebagai contoh:

with open("input", "r") as inp, open("output", "w") as out:
    out.write(inp.read())

Selain itu, saya pribadi menganggap menangkap pengecualian sedini mungkin sebagai kebiasaan buruk. Ini bukan tujuan pengecualian. Jika fungsi IO yang bisa gagal adalah bagian dari operasi yang lebih rumit, dalam banyak kasus IOError harus membatalkan seluruh operasi sehingga ditangani di tingkat luar. Dengan menggunakan withpernyataan, Anda dapat menyingkirkan semua try...finallypernyataan ini di tingkat dalam.

Bernd Petersohn
sumber
7

Jika konten finallyblok ditentukan oleh properti objek file yang dibuka, mengapa pelaksana objek file tidak menjadi orang yang menulis finallyblok? Itulah manfaat dariwith pernyataan tersebut, lebih dari sekadar menghemat tiga baris kode dalam contoh khusus ini.

Dan ya, cara Anda menggabungkan withdan try-exceptmerupakan satu-satunya cara untuk melakukannya, karena kesalahan luar biasa yang disebabkan dalam openpernyataan itu sendiri tidak dapat ditangkap di dalam withblok.

Peter Milley
sumber
1

Saya pikir Anda salah tentang pernyataan "dengan" yang hanya mengurangi garis. Ini sebenarnya melakukan inisialisasi dan menangani pembongkaran.

Dalam kasus Anda "dengan" tidak

  • buka file,
  • memproses isinya, dan
  • pastikan untuk menutupnya.

Berikut ini tautan untuk memahami pernyataan "dengan": http://effbot.org/zone/python-with-statement.htm

Edit: Ya, penggunaan "dengan" Anda benar dan fungsionalitas kedua blok kode itu identik. Pertanyaan tentang mengapa menggunakan "dengan"? itu karena manfaat yang Anda dapatkan dengannya. seperti yang Anda sebutkan tentang f.close () yang hilang secara tidak sengaja.

YoK
sumber
-4

Cara yang lebih Pythonic untuk kode-kode berikut adalah:

try:
    f = open("file", "r")
    try:
        line = f.readline()
    finally:
        f.close()
except IOError:
    <whatever>

try:
    f = open("file", "r")
except IOError:
    <whatever>
else:
    f.close()
Leo Liu
sumber
1
Saya telah menambahkan pemformatan kode untuk Anda; itu membuatnya lebih mudah untuk dibaca. Tetapi Anda mungkin ingin memeriksa ulang untuk memastikan bahwa saya tidak merusak indentasi.
andrewsi
2
Tidak, versi Anda tidak melakukan hal yang sama dengan kode aslinya. Meskipun Anda menambahkan readline()panggilan yang hilang , versi Anda tidak menutup file jika readline()hasilnya adalah IOError.
Aleksi Torhamo