Dalam Python bagaimana saya harus menguji apakah suatu variabel Tidak, Benar atau Salah

146

Saya memiliki fungsi yang dapat mengembalikan satu dari tiga hal:

  • sukses ( True)
  • kegagalan ( False)
  • kesalahan pembacaan / aliran parsing ( None)

Pertanyaan saya adalah, jika saya tidak seharusnya menguji Trueatau False, bagaimana saya harus melihat apa hasilnya. Di bawah ini adalah bagaimana saya saat ini melakukannya:

result = simulate(open("myfile"))
if result == None:
    print "error parsing stream"
elif result == True: # shouldn't do this
    print "result pass"
else:
    print "result fail"

apakah ini benar-benar sesederhana menghapus == Truebagian atau haruskah saya menambahkan tipe data tri-bool. Saya tidak ingin simulatefungsi untuk melemparkan pengecualian karena semua yang saya ingin program luar lakukan dengan kesalahan adalah log dan lanjutkan.

James Brooks
sumber
Anda mengajukan pertanyaan yang salah; Anda harus meminta bantuan untuk mendefinisikan hasil Anda ... apa perbedaan yang Anda rasakan antara "kegagalan" dan "aliran kesalahan penguraian", apa artinya, apa konsekuensinya, tindakan apa yang mungkin ingin diambil oleh penelepon. dalam setiap kasus (lulus, gagal, kesalahan parse)?
John Machin
Saya mensimulasikan sistem tenaga listrik, jika orang kehilangan daya ke rumah mereka, itu adalah kegagalan. Jika saya tidak dapat membaca file simulasi maka itu adalah kesalahan dari jenis yang sama sekali berbeda.
James Brooks
2
Di dalam simulatefungsi saya menangkap semua pengecualian; Saya tidak ingin apa pun yang terjadi di dalam simulator untuk menghentikan sisa program yang sedang berjalan (dan memproses elemen berikutnya). Tetapi jawabannya membuat saya berubah pikiran.
James Brooks
1
@ James Brooks: Benar. Itulah yang dicoba / kecuali diproses. Jika simulatebarang Anda dapat ditangkap dan dicoba lagi, itu bagus. Tetapi jika "gagal", seharusnya tidak kembali None. Seharusnya hanya memunculkan pengecualian pada skrip yang menyebutnya. Either way, simulatedilakukan. Mengembalikan Nonetidak membantu seperti meningkatkan pengecualian yang tepat - atau membiarkan pengecualian menyebar simulateke dalam skrip panggilan untuk ditangani.
S.Lott
1
@ James, gunakan except Exception:saja. Ini menangkap semua kesalahan "nyata", bersama dengan Warningdan StopIteration. Itu memungkinkan KeyboardInterruptdan SystemExitmelaluinya. Jika Anda benar-benar ingin menangkapnya, mungkin lebih baik menggunakan yang lain, coba luar / kecuali atau struktur lain yang dengan jelas mendokumentasikan maksud Anda, karena itu bukan "kesalahan". (Tapi saya mengatakan "hampir tidak pernah" ... mungkin dalam kasus Anda, Anda benar-benar ingin mengambil semuanya, dan bahkan mencegah Ctrl-C atau sys.exit()keluar, dll.)
Peter Hansen

Jawaban:

119

Jangan takut akan Pengecualian! Program Anda baru saja masuk dan melanjutkan semudah:

try:
    result = simulate(open("myfile"))
except SimulationException as sim_exc:
    print "error parsing stream", sim_exc
else:
    if result:
        print "result pass"
    else:
        print "result fail"

# execution continues from here, regardless of exception or not

Dan sekarang Anda dapat memiliki jenis notifikasi yang jauh lebih kaya dari metode simulasi tentang apa yang sebenarnya salah, jika Anda menemukan kesalahan / tidak ada kesalahan yang tidak cukup informatif.

PaulMcG
sumber
Sepakat. Jauh lebih pythonic daripada solusi yang jelas lebih populer di atas (yang berbau terlalu banyak seperti kode C).
Brandon
7
@ Brandon Tidak setuju. Kode ini lebih panjang dan, lebih buruk, kurang dapat dibaca daripada solusi di atas (atau versi yang disempurnakan di bawah): lebih banyak lekukan, lebih banyak pernyataan berbeda - tebak mengapa yang terakhir ini lebih populer, seperti yang Anda katakan ... ;-) Mengapa mencoba menjadi 'Pythonic' jika itu mengarah ke kode yang lebih aneh ...?
Rolf Bartstra
Sekarang cetak traceback alih-alih "aliran kesalahan parsing" dan Anda mendapat suara saya.
CivFan
Oke, Anda mendapatkan suara saya, tetapi saya bermaksud mencetak sesuatu seperti traceback.format_exc() . Lihat jawaban SO ini.
CivFan
11
Banyak orang akan datang ke halaman ini untuk mencari jawaban atas pertanyaan judul. Bagi kebanyakan dari kita, "Jangan takut akan Pengecualian!" tidak ada hubungannya dengan situasi kita. Kita hanya perlu menguji Benar, Salah, dan Tidak Ada. Meskipun alternatif yang Anda sarankan valid untuk beberapa kasus, saya pikir lebih baik memasukkan jawaban atas pertanyaan yang diajukan.
farlysuperiorman
162
if result is None:
    print "error parsing stream"
elif result:
    print "result pass"
else:
    print "result fail"

tetap sederhana dan eksplisit. Tentu saja Anda dapat menentukan kamus terlebih dahulu.

messages = {None: 'error', True: 'pass', False: 'fail'}
print messages[result]

Jika Anda berencana memodifikasi simulatefungsi Anda untuk memasukkan lebih banyak kode kembali, mempertahankan kode ini mungkin menjadi sedikit masalah.

The simulatejuga mungkin meningkatkan pengecualian pada kesalahan parsing, dalam hal ini Anda akan baik akan menangkapnya sini atau membiarkannya menyebarkan tingkat atas dan sedikit pencetakan akan berkurang menjadi satu baris jika-lain pernyataan.

SilentGhost
sumber
1
Yang terakhir adalah semacam tes eksplisit terhadap Benar atau Salah, bukan?
Peter Eisentraut
1
tentu saja, tetapi mengetahui bahwa ini hanya nilai pengembalian yang mungkin, saya tidak berpikir itu masalah.
SilentGhost
dan tampaknya sedikit lebih cepat juga
SilentGhost
a = 'foo' jika a: print 'true' a sebenarnya tidak BENAR, hanya saja tidak ada
wesm
17

Tidak pernah, tidak pernah, tidak pernah mengatakan

if something == True:

Tidak pernah. Ini gila, karena Anda mengulangi apa yang ditentukan secara berlebihan sebagai aturan kondisi redundan untuk pernyataan-if.

Lebih buruk lagi, tetap, tidak pernah, tidak pernah, tidak pernah mengatakan

if something == False:

Kamu punya not. Jangan ragu untuk menggunakannya.

Akhirnya, melakukan a == Noneitu tidak efisien. Lakukan a is None. Noneadalah objek singleton khusus, hanya ada satu. Cukup periksa untuk melihat apakah Anda memiliki objek itu.

S.Lott
sumber
3
Pengujian untuk kesetaraan dengan Truetidak berlebihan (meskipun saya setuju itu tidak masuk akal). Itu bisa memanggil __eq__atau metode khusus lainnya, yang bisa melakukan apa saja secara praktis.
Scott Griffiths
5
@Scott Griffiths: Poin bagus. Itu skenario yang benar-benar dan sangat mengerikan. Jika itu benar-benar terjadi, program ini melanggar ekspektasi dasar kita dengan cara yang membuatnya menjadi sesuatu yang perlu dihapus dan ditulis ulang dari awal tanpa sihir hitam seperti itu.
S.Lott
78
"Tidak pernah, tidak pernah, tidak pernah ..." Namun ada beberapa kasus yang if something == Truemenghasilkan hasil yang berbeda dari if something, misalnya untuk non-boolean something. 2==Truemenghasilkan false sedangkan 2dievaluasi ke true; None==Falseitu salah tetapi not Noneitu benar!
Rolf Bartstra
9
-1 Jawaban ini menyesatkan dan sepenuhnya salah, karena apa yang dikatakan @Rolf Bartstra adalah benar. Meskipun dalam hal ini, apa yang Anda katakan dapat diterapkan.
HelloGoodbye
3
-1. Karena nilai yang tidak nol atau tidak kosong atau tidak nol panjang untuk somethingpengembalian Trueaktif bool(something). Dalam hal ini, jika Anda HANYA ingin memeriksa apakah somethingmemiliki nilai Trueyaitu bool. Maka Anda HARUS melakukan if something == TrueIMO.
Samarth Shah
2

Saya ingin menekankan bahwa, bahkan jika ada situasi di mana if expr :tidak cukup karena salah satu ingin memastikan exprini Truedan tidak hanya berbeda dari 0/ None/ apa pun, isharus disukai dari == untuk alasan yang sama S. Lott mentionned untuk menghindari== None .

Memang sedikit lebih efisien dan, ceri pada kue, lebih dapat dibaca manusia.

In [1]: %timeit (1 == 1) == True
38.1 ns ± 0.116 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

In [2]: %timeit (1 == 1) is True
33.7 ns ± 0.141 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
Thrastylon
sumber
1
Anda tidak dapat menjalankan patokan sekali dan mengatakan bahwa yang satu lebih efisien daripada yang lain (meskipun mungkin). Jalankan berkali-kali (10.000) untuk melihat bagaimana itu berperilaku rata-rata. \
user1767754
1

Saya percaya bahwa melemparkan pengecualian adalah ide yang lebih baik untuk situasi Anda. Alternatifnya adalah metode simulasi untuk mengembalikan tuple. Item pertama akan menjadi status dan yang kedua hasilnya:

result = simulate(open("myfile"))
if not result[0]:
  print "error parsing stream"
else:
  ret= result[1]
kgiannakakis
sumber
1
mengembalikan tuple biasanya berjalan baik dengan membongkar tuple;)
SilentGhost
2
kode Anda, bagaimanapun, tidak masuk akal, jika Falsedikembalikan, itu akan dicetak 'error parsing stream'.
SilentGhost
Metode simulasi harus mengembalikan (False, "anything at all") atau (True, ret) di mana ret adalah False atau True.
kgiannakakis
2
baik, Anda mendefinisikan kembali nilai-nilai output yang sesuai dengan logika Anda, tidak jelas tanpa penjelasan
SilentGhost