Apakah ada cara untuk mengetahui (pada waktu pengkodean) pengecualian mana yang diharapkan saat menjalankan kode python? Saya akhirnya menangkap kelas Pengecualian dasar 90% dari waktu karena saya tidak tahu jenis pengecualian mana yang mungkin dilempar (dan tidak memberitahu saya untuk membaca dokumentasi. Berkali-kali pengecualian dapat disebarkan dari dalam. Dan banyak lagi kali dokumentasi tidak diperbarui atau benar). Apakah ada semacam alat untuk memeriksa ini? (seperti dengan membaca kode python dan libs)?
89
raise
string, bukan hanyaBaseException
subclass. Jadi jika Anda memanggil ke kode perpustakaan yang di luar kendali Anda, bahkanexcept Exception
tidak cukup, karena tidak akan menangkap pengecualian string. Seperti yang ditunjukkan orang lain, Anda menggonggong pohon yang salah di sini.except Exception
berfungsi dengan baik untuk menangkap pengecualian string di Python 2.6 dan yang lebih baru.Jawaban:
Saya kira solusi hanya bisa tidak tepat karena kurangnya aturan pengetikan statis.
Saya tidak mengetahui beberapa alat yang memeriksa pengecualian, tetapi Anda dapat menemukan alat Anda sendiri yang sesuai dengan kebutuhan Anda (peluang bagus untuk bermain sedikit dengan analisis statis).
Sebagai upaya pertama, Anda bisa menulis fungsi yang membangun AST, menemukan semua
Raise
node, dan kemudian mencoba mencari pola umum untuk memunculkan pengecualian (misalnya memanggil konstruktor secara langsung)Biarlah
x
program berikut ini:x = '''\ if f(x): raise IOError(errno.ENOENT, 'not found') else: e = g(x) raise e '''
Bangun AST menggunakan
compiler
paket:Kemudian tentukan
Raise
kelas pengunjung:class RaiseVisitor(object): def __init__(self): self.nodes = [] def visitRaise(self, n): self.nodes.append(n)
Dan berjalan di
Raise
node pengumpul AST :v = RaiseVisitor() compiler.walk(tree, v) >>> print v.nodes [ Raise( CallFunc( Name('IOError'), [Getattr(Name('errno'), 'ENOENT'), Const('not found')], None, None), None, None), Raise(Name('e'), None, None), ]
Anda dapat melanjutkan dengan menyelesaikan simbol menggunakan tabel simbol kompilator, menganalisis dependensi data, dll. Atau Anda dapat menyimpulkan,
CallFunc(Name('IOError'), ...)
"seharusnya berarti menaikkanIOError
", yang cukup OK untuk hasil praktis yang cepat :)sumber
v.nodes
nilai di atas, Anda tidak bisa benar-benar mengatakan, apa ituName('IOError')
atauName('e')
. Anda tidak tahu apa nilai ituIOError
dane
bisa menunjuk, karena mereka disebut variabel bebas. Bahkan jika konteks pengikatannya diketahui (di sini tabel simbol ikut bermain), Anda harus melakukan beberapa jenis analisis ketergantungan data untuk menyimpulkan nilai pastinya (ini harus sulit dilakukan dengan Python).['IOError(errno.ENOENT, "not found")', 'e']
ditampilkan kepada pengguna sudah cukup. Tetapi Anda tidak dapat menyimpulkan kelas aktual dari nilai variabel yang diwakili oleh string :) (maaf telah memposting ulang)exc_class = raw_input(); exec "raise " + exc_class
. Intinya adalah bahwa analisis statis semacam ini tidak benar-benar mungkin dilakukan dalam bahasa dinamis seperti Python.find /path/to/library -name '*.py' | grep 'raise '
mendapatkan hasil yang serupa :)Anda seharusnya hanya menangkap pengecualian yang akan Anda tangani.
Menangkap semua pengecualian berdasarkan jenis konkretnya adalah omong kosong. Anda harus menangkap pengecualian khusus yang dapat dan akan Anda tangani. Untuk pengecualian lain, Anda dapat menulis tangkapan umum yang menangkap "pengecualian dasar", mencatatnya (menggunakan
str()
fungsi) dan menghentikan program Anda (atau melakukan sesuatu yang sesuai dalam situasi macet).Jika Anda benar-benar akan menangani semua pengecualian dan yakin tidak ada yang fatal (misalnya, jika Anda menjalankan kode di semacam lingkungan kotak pasir), maka pendekatan Anda untuk menangkap BaseException generik sesuai dengan tujuan Anda.
Anda mungkin juga tertarik dengan referensi pengecualian bahasa , bukan referensi untuk perpustakaan yang Anda gunakan.
Jika referensi library benar-benar buruk dan tidak menampilkan kembali pengecualiannya sendiri saat menangkap sistem, satu-satunya pendekatan yang berguna adalah menjalankan pengujian (mungkin menambahkannya ke rangkaian pengujian, karena jika ada sesuatu yang tidak terdokumentasi, itu dapat berubah!) . Hapus file penting untuk kode Anda dan periksa pengecualian apa yang dilempar. Berikan terlalu banyak data dan periksa kesalahan apa yang dihasilkannya.
Anda tetap harus menjalankan pengujian, karena, meskipun metode untuk mendapatkan pengecualian dengan kode sumber ada, itu tidak akan memberi Anda ide bagaimana Anda harus menangani semua itu . Mungkin Anda harus menampilkan pesan kesalahan "File needful.txt tidak ditemukan!" kapan kamu menangkap
IndexError
? Hanya tes yang tahu.sumber
Alat yang tepat untuk mengatasi masalah ini adalah unittests. Jika Anda memiliki pengecualian yang dimunculkan oleh kode nyata yang tidak dimunculkan oleh unittests, maka Anda memerlukan lebih banyak unittests.
Pertimbangkan ini
def f(duck): try: duck.quack() except ??? could be anything
bebek bisa menjadi benda apapun
Tentunya Anda dapat memiliki
AttributeError
itik if tidak memiliki dukun,TypeError
bebek if memiliki dukun tetapi tidak dapat dipanggil. Anda tidak tahu apa yangduck.quack()
mungkin timbul, bahkan mungkin aDuckError
atau sesuatuSekarang misalkan Anda memiliki kode seperti ini
Jika memunculkan
IndexError
Anda tidak tahu apakah itu berasal dari arr [i] atau dari dalam fungsi database. biasanya tidak terlalu menjadi masalah di mana pengecualian terjadi, melainkan sesuatu yang salah dan apa yang Anda inginkan tidak terjadi.Teknik praktis adalah menangkap dan mungkin menghidupkan kembali pengecualian seperti ini
except Exception as e #inspect e, decide what to do raise
sumber
Sejauh ini tidak ada yang menjelaskan, mengapa Anda tidak dapat memiliki daftar pengecualian yang lengkap dan 100% benar, jadi saya pikir perlu dikomentari. Salah satu alasannya adalah fungsi kelas satu. Katakanlah Anda memiliki fungsi seperti ini:
def apl(f,arg): return f(arg)
Sekarang
apl
dapat memunculkan pengecualian apa pun yangf
timbul. Meskipun tidak banyak fungsi seperti itu di pustaka inti, apa pun yang menggunakan pemahaman daftar dengan filter khusus, peta, pengurangan, dll. Akan terpengaruh.Dokumentasi dan penganalisis sumber adalah satu-satunya sumber informasi yang "serius" di sini. Ingatlah apa yang tidak bisa mereka lakukan.
sumber
Saya mengalami ini ketika menggunakan soket, saya ingin mengetahui semua kondisi kesalahan yang akan saya hadapi (jadi daripada mencoba membuat kesalahan dan mencari tahu soket apa yang saya hanya ingin daftar ringkas). Akhirnya saya akhirnya grep'ing "/usr/lib64/python2.4/test/test_socket.py" untuk "meningkatkan":
$ grep raise test_socket.py Any exceptions raised by the clients during their tests raise TypeError, "test_func must be a callable function" raise NotImplementedError, "clientSetUp must be implemented." def raise_error(*args, **kwargs): raise socket.error def raise_herror(*args, **kwargs): raise socket.herror def raise_gaierror(*args, **kwargs): raise socket.gaierror self.failUnlessRaises(socket.error, raise_error, self.failUnlessRaises(socket.error, raise_herror, self.failUnlessRaises(socket.error, raise_gaierror, raise socket.error # Check that setting it to an invalid value raises ValueError # Check that setting it to an invalid type raises TypeError def raise_timeout(*args, **kwargs): self.failUnlessRaises(socket.timeout, raise_timeout, def raise_timeout(*args, **kwargs): self.failUnlessRaises(socket.timeout, raise_timeout,
Yang merupakan daftar kesalahan yang cukup ringkas. Sekarang tentu saja ini hanya bekerja berdasarkan kasus per kasus dan tergantung pada tes yang akurat (yang biasanya memang demikian). Jika tidak, Anda perlu menangkap semua pengecualian, mencatatnya dan membedahnya dan mencari cara untuk menanganinya (yang dengan pengujian unit tidak akan sulit).
sumber
There are two ways that I found informative. The first one, run the code in iPython, which will display the exception type.
n = 2 str = 'me ' str + 2 TypeError: unsupported operand type(s) for +: 'int' and 'str'
In the second way we settle for catching too much and improve on it over time. Include a
try
expression in your code and catchexcept Exception as err
. Print sufficient data to know what exception was thrown. As exceptions are thrown improve your code by adding a more preciseexcept
clause. When you feel that you have caught all relevant exceptions remove the all inclusive one. A good thing to do anyway because it swallows programming errors.try: so something except Exception as err: print "Some message" print err.__class__ print err exit(1)
sumber
biasanya, Anda hanya perlu menangkap pengecualian di sekitar beberapa baris kode. Anda tidak ingin memasukkan seluruh
main
fungsi Anda ke dalamtry except
klausa. untuk setiap beberapa baris Anda harus selalu sekarang (atau dapat dengan mudah memeriksa) jenis pengecualian apa yang mungkin dimunculkan.docs memiliki daftar lengkap pengecualian bawaan . jangan mencoba untuk kecuali pengecualian yang tidak Anda harapkan, mereka mungkin ditangani / diharapkan dalam kode panggilan.
edit : apa yang mungkin terlempar tergantung pada apa yang Anda lakukan! mengakses elemen acak dari sebuah urutan
IndexError
:, elemen acak dari sebuah dict:,KeyError
dll.Coba saja jalankan beberapa baris itu di IDLE dan buat pengecualian. Tapi unittest akan menjadi solusi yang lebih baik, tentu saja.
sumber