Python - menegaskan vs jika & kembali

12

Saya menulis skrip yang melakukan sesuatu pada file teks (apa yang dilakukannya tidak relevan untuk pertanyaan saya). Jadi sebelum saya melakukan sesuatu pada file saya ingin memeriksa apakah file itu ada. Saya bisa melakukan ini, tidak ada masalah, tetapi masalahnya lebih pada estetika.

Ini kode saya, menerapkan hal yang sama dalam dua cara berbeda.

def modify_file(filename):
    assert os.path.isfile(filename), 'file does NOT exist.'


Traceback (most recent call last):
  File "clean_files.py", line 15, in <module>
    print(clean_file('tes3t.txt'))
  File "clean_files.py", line 8, in clean_file
    assert os.path.isfile(filename), 'file does NOT exist.'
AssertionError: file does NOT exist.

atau:

def modify_file(filename):
    if not os.path.isfile(filename):
        return 'file does NOT exist.'


file does NOT exist.

Metode pertama menghasilkan output yang sebagian besar sepele, satu-satunya hal yang saya pedulikan adalah bahwa file tersebut tidak ada.

Metode kedua mengembalikan string, itu sederhana.

Pertanyaan saya adalah: metode mana yang lebih baik untuk memberi tahu pengguna bahwa file tersebut tidak ada? Menggunakan assertmetode ini sepertinya lebih bersifat pythonic.

Vader
sumber

Jawaban:

33

Anda akan memilih opsi ketiga : gunakan raisedan pengecualian khusus. Ini bisa menjadi salah satu pengecualian bawaan , atau Anda dapat membuat pengecualian khusus untuk pekerjaan itu.

Dalam hal ini, saya akan menggunakan IOError, tetapi ValueErrormungkin juga cocok:

def modify_file(filename):
    if not os.path.isfile(filename):
        raise IOError('file does NOT exist.')

Menggunakan pengecualian khusus memungkinkan Anda untuk meningkatkan pengecualian lain untuk keadaan luar biasa yang berbeda, dan memungkinkan penelepon menangani pengecualian dengan anggun.

Tentu saja, banyak operasi file (seperti open()) sendiriOSError sudah meningkat ; pengujian eksplisit pertama jika file ada mungkin berlebihan di sini.

Jangan gunakan assert; jika Anda menjalankan python dengan -Oflag, semua pernyataan dilucuti dari kode.

Martijn Pieters
sumber
poin menarik tentang redundansi! Apakah Anda merekomendasikan untuk menghindarinya? yaitu "nanti akan gagal"
Ciprian Tomoiagă
1
@ CiprianTomoiagă: mengapa harus melakukan tes? Jika baris berikutnya modify_file()adalah with open(filename) as f:, maka IOErrorjuga akan dinaikkan. Dan versi Python yang lebih baru telah memberikan lebih banyak detail dalam subclass IOError( FileNotFoundErrorkhususnya yang muncul di benak) yang dapat membantu pengembang menggunakan API ini. Jika kode melakukan pemeriksaan dan menaikkan sendiri IOErrormaka detail yang bermanfaat akan hilang.
Martijn Pieters
@ MartijnPieters akan jawaban yang dapat diterima untuk "mengapa meringkuk pada tes?" menjadi saat ketika pemeriksaan pertama lebih cepat dari pengecualian yang diajukan saat open () gagal? misalnya ketika memeriksa keberadaan file lebih cepat daripada mencoba untuk membuka dan akhirnya gagal melakukannya.
Marcel Wilson
1
@ MarscelWilson: Tidak, karena Anda akan mengoptimalkan mikro terhadap metode yang dilakukan I / O. Tidak ada jumlah tweaker dalam semantik Python akan membuat I / O lebih cepat, dan hanya merusak keterbacaan dan pemeliharaan. Fokuslah pada area dengan dampak lebih besar, kataku.
Martijn Pieters
12

assertdimaksudkan untuk kasus-kasus di mana pemrogram memanggil fungsi membuat kesalahan, sebagai lawan pengguna . Menggunakan di assertbawah keadaan itu memungkinkan Anda untuk memastikan seorang programmer menggunakan fungsi Anda dengan benar selama pengujian, tetapi kemudian menghapusnya dalam produksi.

Nilainya agak terbatas karena Anda harus memastikan bahwa Anda menjalankan jalur itu melalui kode, dan Anda sering ingin juga menangani masalah dengan ifpernyataan terpisah dalam produksi. assertpaling berguna dalam situasi seperti, "Saya ingin membantu mengatasi masalah ini jika pengguna memukulnya, tetapi jika pengembang memukulnya, saya ingin itu macet keras sehingga dia akan memperbaiki kode yang menyebut fungsi ini tidak benar."

Dalam kasus khusus Anda, file yang hilang hampir pasti merupakan kesalahan pengguna, dan harus ditangani dengan memunculkan pengecualian.

Karl Bielefeldt
sumber
5

Dari UsingAssertionsEffective

Memeriksa isinstance () tidak boleh digunakan secara berlebihan: jika itu dukun seperti bebek, mungkin tidak perlu bertanya terlalu dalam ke apakah itu benar-benar. Terkadang berguna untuk memberikan nilai yang tidak diantisipasi oleh programmer asli.

Tempat untuk mempertimbangkan menempatkan pernyataan:

checking parameter types, classes, or values
checking data structure invariants
checking "can't happen" situations (duplicates in a list, contradictory state variables.)
after calling a function, to make sure that its return is reasonable 

Intinya secara keseluruhan adalah bahwa jika ada yang tidak beres, kami ingin membuatnya sepenuhnya jelas sesegera mungkin.

Lebih mudah untuk menangkap data yang salah pada titik masuknya daripada mengetahui bagaimana data itu sampai nanti ketika menyebabkan masalah.

Pernyataan bukan merupakan pengganti untuk tes unit atau tes sistem, tetapi lebih sebagai pelengkap. Karena pernyataan adalah cara bersih untuk memeriksa keadaan internal suatu objek atau fungsi, mereka memberikan "secara gratis" bantuan kotak-jelas untuk pengujian kotak-hitam yang memeriksa perilaku eksternal.

Pernyataan tidak boleh digunakan untuk menguji kasus kegagalan yang dapat terjadi karena input pengguna yang buruk atau kegagalan sistem operasi / lingkungan, seperti file yang tidak ditemukan. Sebagai gantinya, Anda harus mengajukan pengecualian, atau mencetak pesan kesalahan, atau apa pun yang sesuai. Satu alasan penting mengapa asersi hanya boleh digunakan untuk swa-uji program adalah bahwa asersi dapat dinonaktifkan pada waktu kompilasi.

Jika Python dimulai dengan opsi -O, maka pernyataan akan dihapus dan tidak dievaluasi. Jadi jika kode banyak menggunakan pernyataan, tetapi kinerja-kritis, maka ada sistem untuk mematikannya dalam rilis rilis. (Tapi jangan lakukan ini kecuali itu benar-benar diperlukan. Sudah terbukti secara ilmiah bahwa beberapa bug hanya muncul ketika pelanggan menggunakan mesin dan kami ingin pernyataan untuk membantu di sana juga. :-))

dspjm
sumber