Apakah ada masalah kinerja atau pemeliharaan kode dengan penggunaan
assert
sebagai bagian dari kode standar alih-alih menggunakannya hanya untuk keperluan debugging?Adalah
assert x >= 0, 'x is less than zero'
lebih baik atau lebih buruk daripada
if x < 0: raise Exception, 'x is less than zero'
Juga, apakah ada cara untuk menetapkan aturan bisnis seperti
if x < 0 raise error
itu selalu diperiksa tanpatry/except/finally
jadi, jika kapan saja seluruh kodex
kurang dari 0 kesalahan dinaikkan, seperti jika Anda menetapkanassert x < 0
pada awal fungsi, di mana saja dalam fungsi di manax
menjadi kurang dari 0 pengecualian dimunculkan?
483
assert
.Jawaban:
Untuk dapat secara otomatis melempar kesalahan ketika x menjadi kurang dari nol di seluruh fungsi. Anda dapat menggunakan deskriptor kelas . Berikut ini sebuah contoh:
sumber
Pernyataan harus digunakan untuk menguji kondisi yang seharusnya tidak pernah terjadi . Tujuannya adalah untuk crash awal dalam kasus program yang korup.
Pengecualian harus digunakan untuk kesalahan yang bisa terjadi, dan Anda hampir selalu harus membuat kelas Pengecualian Anda sendiri .
Misalnya, jika Anda menulis fungsi untuk dibaca dari file konfigurasi menjadi a
dict
, pemformatan yang tidak benar dalam file tersebut akan menimbulkan aConfigurationSyntaxError
, sementara Anda dapat melakukannyaassert
Anda tidak akan kembaliNone
.Dalam contoh Anda, jika
x
nilai ditetapkan melalui antarmuka pengguna atau dari sumber eksternal, pengecualian adalah yang terbaik.Jika
x
hanya diatur oleh kode Anda sendiri dalam program yang sama, lanjutkan dengan pernyataan.sumber
assert
berisi implisitif __debug__
dan dapat dioptimalkan pergi - sebagai jawaban John Mee negaraPernyataan "menegaskan" dihapus ketika kompilasi dioptimalkan . Jadi, ya, ada perbedaan kinerja dan fungsional.
Jika Anda menggunakan
assert
untuk mengimplementasikan fungsionalitas aplikasi, kemudian mengoptimalkan penyebaran ke produksi, Anda akan terganggu oleh cacat "but-it-works-in-dev".Lihat PYTHONOPTIMIZE dan -O -OO
sumber
raise
sebagaiException
gantinya. Oh - Saya baru saja menemukan nama yang tepatSuspiciousOperation
Exception
dengan subclass diDjango
! Sempurna!bandit
kode Anda, itu akan memperingatkan Anda tentang hal ini.Empat tujuan dari
assert
Asumsikan Anda bekerja pada 200.000 baris kode dengan empat rekan kerja Alice, Bernd, Carl, dan Daphne. Mereka memanggil kode Anda, Anda memanggil kode mereka.
Kemudian
assert
memiliki empat peran :Beri tahu Alice, Bernd, Carl, dan Daphne apa yang diharapkan kode Anda.
Asumsikan Anda memiliki metode yang memproses daftar tupel dan logika program bisa pecah jika tupel itu tidak berubah:
Ini lebih dapat dipercaya daripada informasi yang setara dalam dokumentasi dan jauh lebih mudah untuk dipelihara.
Beri tahu komputer apa yang diharapkan kode Anda.
assert
memberlakukan perilaku yang tepat dari penelepon kode Anda. Jika kode Anda menyebut kode Alices dan Bernd menyebut kode Anda, maka tanpa ituassert
, jika program mogok dalam kode Alices, Bernd mungkin menganggap itu salah Alice, Alice menyelidiki dan mungkin menganggap itu salah Anda, Anda menyelidiki dan memberi tahu Bernd bahwa itu sebenarnya nya. Banyak pekerjaan hilang.Dengan penegasan, siapa pun yang mendapat telepon salah, mereka akan dengan cepat dapat melihat bahwa itu adalah kesalahan mereka, bukan milik Anda. Alice, Bernd, dan kalian semua mendapat manfaat. Menghemat banyak waktu.
Beri tahu pembaca kode Anda (termasuk diri Anda sendiri) apa yang telah dicapai kode Anda di beberapa titik.
Anggaplah Anda memiliki daftar entri dan masing-masingnya dapat bersih (yang baik) atau dapat berupa smorsh, trale, gullup, atau berkelap-kelip (yang semuanya tidak dapat diterima). Jika itu smorsh, itu harus tidak dipilah; jika itu basi, itu harus baludo; jika itu gullup, itu harus ditelusuri (dan kemudian mungkin berjalan juga); jika berbinar-binar itu harus berbinar lagi kecuali pada hari Kamis. Anda mendapat ide: Ini hal yang rumit. Tetapi hasil akhirnya adalah (atau seharusnya) bahwa semua entri bersih. Right Thing (TM) yang harus dilakukan adalah merangkum efek dari loop pembersihan Anda sebagai
Pernyataan ini menghemat sakit kepala bagi semua orang yang mencoba memahami apa sebenarnya yang dicapai lingkaran luar biasa itu. Dan yang paling sering dari orang-orang ini kemungkinan adalah diri Anda sendiri.
Beri tahu komputer apa yang telah dicapai kode Anda di beberapa titik.
Jika Anda pernah lupa untuk mempercepat entri yang membutuhkannya setelah berlari, itu
assert
akan menghemat hari Anda dan menghindari bahwa kode Anda rusak Daphne jauh nanti.Dalam pikiran saya,
assert
dua tujuan dokumentasi (1 dan 3) dan perlindungan (2 dan 4) sama-sama berharga.Memberitahu orang-orang bahkan mungkin lebih berharga daripada memberi informasi kepada komputer karena hal itu dapat mencegah kesalahan yang
assert
ingin ditangkap (dalam kasus 1) dan banyak kesalahan selanjutnya dalam kasus apa pun.sumber
Selain jawaban lain, menegaskan diri mereka melemparkan pengecualian, tetapi hanya AssertionErrors. Dari sudut pandang utilitarian, pernyataan tidak cocok ketika Anda membutuhkan kendali butir halus atas pengecualian yang Anda tangkap.
sumber
AssertionErrors
, ketika Anda setuju dengan itu yang berbutir kasar. Pada kenyataannya, Anda seharusnya tidak menangkap mereka.Satu-satunya hal yang benar-benar salah dengan pendekatan ini adalah sulit untuk membuat pengecualian yang sangat deskriptif menggunakan pernyataan tegas. Jika Anda mencari sintaks yang lebih sederhana, ingat Anda juga dapat melakukan sesuatu seperti ini:
Masalah lain adalah bahwa menggunakan menegaskan untuk memeriksa kondisi normal adalah bahwa itu membuatnya sulit untuk menonaktifkan menegaskan debugging menggunakan flag -O.
sumber
Kata bahasa Inggris menegaskan di sini digunakan dalam arti bersumpah , menegaskan , mengakui . Itu tidak berarti "centang" atau "harus" . Ini berarti bahwa Anda sebagai pembuat kode membuat pernyataan tersumpah di sini:
Jika kodenya benar, kecuali gangguan acara tunggal , kegagalan perangkat keras dan semacamnya, tidak ada pernyataan yang akan gagal . Itulah sebabnya perilaku program kepada pengguna akhir tidak boleh terpengaruh. Terutama, sebuah pernyataan tidak dapat gagal bahkan di bawah kondisi program yang luar biasa . Itu tidak pernah terjadi. Jika itu terjadi, programmer harus di-zapping untuk itu.
sumber
Seperti yang telah dikatakan sebelumnya, pernyataan harus digunakan ketika kode Anda TIDAK HARUS mencapai titik, yang berarti ada bug di sana. Mungkin alasan paling berguna yang bisa saya lihat untuk menggunakan pernyataan adalah invarian / pra / postkondisi. Ini adalah sesuatu yang harus benar pada awal atau akhir setiap iterasi dari suatu loop atau fungsi.
Misalnya, fungsi rekursif (2 fungsi terpisah sehingga 1 menangani input buruk dan yang lainnya menangani kode buruk, menyebabkan sulit dibedakan dengan rekursi). Ini akan memperjelas jika saya lupa menulis pernyataan if, apa yang salah.
Invarian loop ini sering dapat diwakili dengan pernyataan.
sumber
#precondition: n >= 0
dan menegaskan, dia bisa menulis@precondition(lambda n: n >= 0)
__doc__
atribut dengan memberikan string tambahanApakah ada masalah kinerja?
Harap ingat untuk "membuatnya bekerja terlebih dahulu sebelum Anda membuatnya bekerja cepat" .
Sangat sedikit persen dari setiap program biasanya relevan dengan kecepatannya. Anda selalu dapat mengusir atau menyederhanakan
assert
jika terbukti menjadi masalah kinerja - dan kebanyakan dari mereka tidak akan pernah melakukannya.Bersikap pragmatis :
Asumsikan Anda memiliki metode yang memproses daftar tupel yang tidak kosong dan logika program akan pecah jika tupel tersebut tidak dapat diubah. Anda harus menulis:
Ini mungkin baik jika daftar Anda cenderung panjang sepuluh entri, tetapi bisa menjadi masalah jika mereka memiliki sejuta entri. Tetapi alih-alih membuang cek yang berharga ini, Anda cukup menurunkannya
yang murah tetapi kemungkinan akan menangkap sebagian besar kesalahan program yang sebenarnya .
sumber
assert(len(listOfTuples)==0 or type(listOfTyples[0])==tuple)
.Baiklah, ini adalah pertanyaan terbuka, dan saya memiliki dua aspek yang ingin saya sentuh: kapan menambahkan pernyataan dan bagaimana menulis pesan kesalahan.
Tujuan
Untuk menjelaskannya kepada pemula - pernyataan adalah pernyataan yang dapat menimbulkan kesalahan, tetapi Anda tidak akan menangkapnya. Dan mereka biasanya tidak harus dibangkitkan, tetapi dalam kehidupan nyata terkadang mereka memang dibesarkan. Dan ini adalah situasi serius, di mana kode tidak dapat dipulihkan dari, apa yang kita sebut 'kesalahan fatal'.
Selanjutnya, ini untuk 'tujuan debugging', yang, meskipun benar, terdengar sangat meremehkan. Saya suka formulasi 'menyatakan invarian, yang tidak boleh dilanggar' lebih baik, meskipun bekerja secara berbeda pada pemula yang berbeda ... Beberapa 'hanya mengerti', dan yang lain tidak menemukan gunanya, atau mengganti pengecualian normal, atau bahkan mengendalikan aliran dengannya.
Gaya
Dalam Python,
assert
adalah pernyataan, bukan fungsi! (ingatassert(False, 'is true')
tidak akan naik. Tapi, memiliki itu keluar dari jalan:Kapan, dan bagaimana, menulis 'pesan kesalahan' opsional?
Ini berlaku untuk kerangka pengujian unit, yang sering memiliki banyak metode khusus untuk melakukan asersi (
assertTrue(condition)
,assertFalse(condition), assertEqual(actual, expected)
dll.). Mereka sering juga menyediakan cara untuk mengomentari pernyataan tersebut.Dalam kode dibuang Anda bisa melakukannya tanpa pesan kesalahan.
Dalam beberapa kasus, tidak ada yang ditambahkan ke pernyataan:
def dump (sesuatu): nyatakan isinstance (sesuatu, Dumpable) # ...
Namun terlepas dari itu, pesan berguna untuk komunikasi dengan programmer lain (yang kadang-kadang pengguna interaktif kode Anda, misalnya dalam Ipython / Jupyter dll.).
Beri mereka informasi, bukan hanya membocorkan detail implementasi internal.
dari pada:
menulis:
atau bahkan mungkin:
Saya tahu, saya tahu - ini bukan kasus untuk pernyataan statis, tetapi saya ingin menunjukkan nilai informasi dari pesan tersebut.
Pesan negatif atau positif?
Ini mungkin kontroversial, tetapi saya sakit membaca hal-hal seperti:
ini adalah dua hal yang saling bertentangan yang ditulis di sebelah satu sama lain. Jadi setiap kali saya memiliki pengaruh pada basis kode, saya mendorong untuk menentukan apa yang kita inginkan, dengan menggunakan kata kerja tambahan seperti 'harus' dan 'harus', dan tidak mengatakan apa yang tidak kita inginkan.
menyatakan a == b, 'a harus sama dengan b'
Kemudian, mendapatkan
AssertionError: a must be equal to b
juga dapat dibaca, dan pernyataan itu terlihat logis dalam kode. Juga, Anda bisa mendapatkan sesuatu darinya tanpa membaca traceback (yang kadang-kadang bahkan tidak tersedia).sumber
Baik penggunaan
assert
maupun peningkatan pengecualian adalah tentang komunikasi.Penegasan adalah pernyataan tentang kebenaran kode yang ditujukan pada pengembang : Penegasan dalam kode memberi informasi kepada pembaca tentang kode yang harus dipenuhi agar kode tersebut benar. Pernyataan yang gagal saat dijalankan menginformasikan pengembang bahwa ada cacat dalam kode yang perlu diperbaiki.
Pengecualian adalah indikasi tentang situasi non-tipikal yang dapat terjadi pada saat run-time tetapi tidak dapat diselesaikan dengan kode yang ada, yang ditujukan pada kode panggilan yang akan ditangani di sana. Munculnya pengecualian tidak menunjukkan bahwa ada bug dalam kode.
Oleh karena itu, jika Anda menganggap terjadinya situasi tertentu pada saat run-time sebagai bug yang ingin Anda beri tahu pengembang tentang ("Hai pengembang, kondisi ini menunjukkan bahwa ada bug di suatu tempat, perbaiki kodenya.") Lalu pergi untuk pernyataan. Jika pernyataan memeriksa argumen input dari kode Anda, Anda biasanya harus menambahkan ke dokumentasi bahwa kode Anda memiliki "perilaku tidak terdefinisi" ketika argumen input melanggar kondisi itu.
Jika alih-alih kejadian dari situasi yang sama itu bukan indikasi bug di mata Anda, tetapi sebaliknya (mungkin jarang tetapi) situasi yang mungkin Anda pikir harus ditangani oleh kode klien, ajukan pengecualian. Situasi ketika pengecualian yang diajukan harus menjadi bagian dari dokumentasi kode masing-masing.
Evaluasi pernyataan membutuhkan waktu. Mereka dapat dihilangkan pada waktu kompilasi. Ini memiliki beberapa konsekuensi, namun lihat di bawah.
Biasanya pernyataan meningkatkan rawatan kode, karena mereka meningkatkan keterbacaan dengan membuat asumsi eksplisit dan selama waktu berjalan secara teratur memverifikasi asumsi ini. Ini juga akan membantu menangkap regresi. Namun ada satu masalah yang perlu diingat: Ekspresi yang digunakan dalam asersi tidak boleh memiliki efek samping. Seperti disebutkan di atas, pernyataan dapat dihilangkan pada waktu kompilasi - yang berarti bahwa juga efek samping potensial akan hilang. Ini dapat - tanpa sengaja - mengubah perilaku kode.
sumber
Assert adalah untuk memeriksa -
1. kondisi yang valid,
2. pernyataan yang valid,
3. true logic;
kode sumber. Alih-alih gagal seluruh proyek itu memberikan alarm bahwa ada sesuatu yang tidak sesuai dalam file sumber Anda.
Dalam contoh 1, karena variabel 'str' bukan nol. Jadi tidak ada pernyataan atau pengecualian yang diajukan.
Contoh 1:
Dalam contoh 2, var 'str' adalah nol. Jadi kami menyelamatkan pengguna dari melanjutkan program yang salah dengan pernyataan tegas .
Contoh 2:
Saat kita tidak ingin men-debug dan menyadari masalah pernyataan dalam kode sumber. Nonaktifkan bendera optimisasi
python -O assertStatement.py
tidak ada yang akan dicetak
sumber
Dalam IDE seperti PTVS, PyCharm,
assert isinstance()
pernyataan Wing dapat digunakan untuk mengaktifkan penyelesaian kode untuk beberapa objek yang tidak jelas.sumber
typing.cast
.Untuk apa nilainya, jika Anda berurusan dengan kode yang mengandalkan
assert
berfungsi dengan benar, maka menambahkan kode berikut akan memastikan bahwa pernyataan diaktifkan:sumber