Saya memiliki metode yang memanggil 4 metode lain secara berurutan untuk memeriksa kondisi tertentu, dan segera kembali (tidak memeriksa yang berikut) setiap kali seseorang mengembalikan sesuatu yang Sejati.
def check_all_conditions():
x = check_size()
if x:
return x
x = check_color()
if x:
return x
x = check_tone()
if x:
return x
x = check_flavor()
if x:
return x
return None
Ini sepertinya banyak kode bagasi. Alih-alih setiap pernyataan 2-baris jika, saya lebih suka melakukan sesuatu seperti:
x and return x
Tapi itu Python tidak valid. Apakah saya melewatkan solusi sederhana dan elegan di sini? Kebetulan, dalam situasi ini, keempat metode pemeriksaan mungkin mahal, jadi saya tidak ingin memanggil mereka beberapa kali.
python
if-statement
Bernard
sumber
sumber
x and return x
lebih baik daripadaif x: return x
? Yang terakhir jauh lebih mudah dibaca dan dengan demikian dapat dipertahankan. Anda tidak perlu terlalu khawatir tentang jumlah karakter atau garis; jumlah keterbacaan. Mereka adalah jumlah karakter non-spasi yang sama persis, dan jika Anda benar-benar harus,if x: return x
akan bekerja dengan baik hanya pada satu baris.x
(berlawanan denganbool(x)
) sehingga saya kira aman untuk menganggap bahwa fungsi OP dapat mengembalikan apa pun, dan dia menginginkan apa pun yang benar yang benar.Jawaban:
Anda bisa menggunakan loop:
Ini memiliki keuntungan tambahan yang sekarang Anda dapat membuat jumlah kondisi menjadi variabel.
Anda bisa menggunakan
map()
+filter()
(versi Python 3, menggunakanfuture_builtins
versi dalam Python 2) untuk mendapatkan nilai pencocokan pertama seperti:tetapi jika ini lebih mudah dibaca bisa diperdebatkan.
Pilihan lain adalah menggunakan ekspresi generator:
sumber
any
bukan loop.return any(condition() for condition in conditions)
any
memiliki implementasi yang hampir sama di dalam. Tapi kelihatannya jauh lebih baik, silakan posting sebagai jawaban)conditions
danarguments
? Ini IMHO jauh lebih buruk daripada kode asli, yang membutuhkan waktu sekitar 10 detik untuk diurai oleh brainparser saya.return next((check for check in checks if check), None)
.Atau sebagai jawaban baik Martijn, Anda bisa berantai
or
. Ini akan mengembalikan nilai kebenaran pertama, atauNone
jika tidak ada nilai kebenaran:Demo:
sumber
\
untuk menaruh setiap cek pada barisnya sendiri.\
untuk memperpanjang garis logis. Sebaliknya, gunakan tanda kurung; jadireturn (....)
dengan baris baru dimasukkan sesuai kebutuhan. Namun, itu akan menjadi satu baris logis yang panjang.Jangan ubah itu
Ada cara lain untuk melakukan ini sebagaimana ditunjukkan oleh berbagai jawaban lainnya. Tidak ada yang sejelas kode asli Anda.
sumber
:
, karena saya anggapif x: return x
cukup baik, dan itu membuat fungsi terlihat lebih kompak. Tapi itu mungkin hanya aku.or
sebagai timgeb lakukan adalah ungkapan yang tepat dan dipahami dengan baik. Banyak bahasa memiliki ini; mungkin ketika disebutorelse
itu bahkan lebih jelas, tetapi bahkan tuaor
(atau||
dalam bahasa lain) yang biasa dimaksudkan untuk dipahami sebagai alternatif untuk mencoba jika yang pertama "tidak berhasil."or
berlabel un-Pythonic atau dengan cara apa pun dikaburkan, tapi itu masalah pendapat pula --- sebagaimana mestinya.Secara efektif jawaban yang sama dengan timgeb, tetapi Anda bisa menggunakan tanda kurung untuk pemformatan yang lebih baik:
sumber
Menurut hukum Curly , Anda dapat membuat kode ini lebih mudah dibaca dengan membagi dua masalah:
menjadi dua fungsi:
Ini menghindari:
... sembari mempertahankan alur yang linier dan mudah dibaca.
Anda mungkin juga dapat membuat nama fungsi yang lebih baik, sesuai dengan keadaan khusus Anda, yang membuatnya lebih mudah dibaca.
sumber
return None
tidak perlu, karena fungsi kembaliNone
secara default. Namun, tidak ada yang salah dengan kembaliNone
secara eksplisit, dan saya suka Anda memilih untuk melakukannya.Ini adalah varian dari Martijns, contoh pertama. Ini juga menggunakan "koleksi callable" -style untuk memungkinkan hubungan arus pendek.
Alih-alih loop Anda bisa menggunakan builtin
any
.Perhatikan bahwa
any
mengembalikan boolean, jadi jika Anda membutuhkan nilai pengembalian yang tepat dari cek, solusi ini tidak akan berfungsi.any
tidak akan membedakan antara14
,'red'
,'sharp'
,'spicy'
sebagai nilai-nilai kembali, mereka semua akan dikembalikan sebagaiTrue
.sumber
next(itertools.ifilter(None, (c() for c in conditions)))
untuk mendapatkan nilai aktual tanpa membuangnya ke boolean.any
sebenarnya hubungan arus pendek?x = bar(); if x: return x;
Sudahkah Anda mempertimbangkan untuk menulis
if x: return x
semuanya dalam satu baris?Ini tidak kurang berulang dari apa yang Anda miliki, tetapi IMNSHO bunyinya sedikit lebih lancar.
sumber
Saya cukup terkejut tidak ada yang menyebutkan built-in
any
yang dibuat untuk tujuan ini:Perhatikan bahwa meskipun implementasi ini mungkin yang paling jelas, ia mengevaluasi semua pemeriksaan bahkan jika yang pertama adalah
True
.Jika Anda benar-benar harus berhenti di cek gagal pertama, pertimbangkan untuk menggunakan
reduce
yang dibuat untuk mengkonversi daftar ke nilai sederhana:Dalam kasus Anda:
lambda a, f: a or f()
adalah fungsi yang memeriksa apakah akumulatora
atau cek saatf()
iniTrue
. Perhatikan bahwa jikaa
adalahTrue
,f()
tidak akan dievaluasi.checks
berisi fungsi pemeriksaan (thef
item dari lambda)False
adalah nilai awal, jika tidak cek tidak akan terjadi dan hasilnya akan selaluTrue
any
danreduce
merupakan alat dasar untuk pemrograman fungsional. Saya sangat mendorong Anda untuk melatih ini danmap
yang juga luar biasa!sumber
any
hanya berfungsi jika cek benar-benar mengembalikan nilai boolean, secara harfiahTrue
atauFalse
, tetapi pertanyaannya tidak menentukan itu. Anda harus menggunakanreduce
untuk mengembalikan nilai aktual yang dikembalikan oleh cek. Juga, cukup mudah untuk menghindari mengevaluasi semua cek denganany
menggunakan generator, misany(c() for c in (check_size, check_color, check_tone, check_flavor))
. Seperti dalam jawaban Leonhardreduce
. Seperti @ DavidZ, saya percaya solusi Andaany
harus menggunakan generator dan perlu ditunjukkan bahwa itu terbatas untuk mengembalikanTrue
atauFalse
.any
bekerja dengan nilai-nilai yang benar:any([1, "abc", False]) == True
danany(["", 0]) == False
any
hanya bekerja untuk itu dimaksudkan jika nilai-nilai boolean yang sebenarnya dikembalikan dari fungsi cek.Jika Anda menginginkan struktur kode yang sama, Anda bisa menggunakan pernyataan ternary!
Saya pikir ini terlihat bagus dan jelas jika Anda melihatnya.
Demo:
sumber
x if x else <something>
hanya dapat direduksi menjadix or <something>
Bagi saya, jawaban terbaik adalah dari @ phil-frost, diikuti oleh @ wayne-werner's.
Apa yang saya temukan menarik adalah bahwa tidak ada yang mengatakan apa-apa tentang fakta bahwa suatu fungsi akan mengembalikan banyak tipe data yang berbeda, yang akan membuat wajib untuk melakukan pemeriksaan pada tipe x itu sendiri untuk melakukan pekerjaan lebih lanjut.
Jadi saya akan mencampur respon @ PhilFrost dengan ide menjaga satu tipe:
Perhatikan bahwa
x
dilewatkan sebagai argumen, tetapi jugaall_conditions
digunakan sebagai generator lulus dari fungsi pemeriksaan di mana semuanya mendapatkanx
diperiksa, dan kembaliTrue
atauFalse
. Dengan menggunakanfunc
denganall_conditions
sebagai nilai default, Anda dapat menggunakanassessed_x(x)
, atau Anda dapat melewati generator pribadi lebih lanjut melaluifunc
.Dengan begitu, Anda mendapatkan
x
begitu satu cek berlalu, tetapi itu akan selalu menjadi tipe yang sama.sumber
Idealnya, saya akan menulis ulang
check_
fungsi untuk mengembalikanTrue
atauFalse
daripada nilai. Cek Anda kemudian menjadiDengan asumsi Anda
x
tidak dapat diubah, fungsi Anda masih dapat memodifikasinya (meskipun mereka tidak dapat menugaskannya kembali) - tetapi fungsi yang dipanggilcheck
tidak boleh benar-benar memodifikasinya.sumber
Sedikit variasi pada Martijns contoh pertama di atas, yang menghindari if di dalam loop:
sumber
Status or c()
akan melewati / melakukan hubungan pendek mengevaluasi panggilan kec()
jikaStatus
benar, sehingga kode dalam jawaban ini tampaknya tidak memanggil lebih banyak fungsi daripada kode OP. stackoverflow.com/questions/2580136/…Saya suka @ timgeb. Sementara itu saya ingin menambahkan bahwa mengekspresikan
None
dalamreturn
pernyataan tidak diperlukan karena kumpulanor
pernyataan terpisah dievaluasi dan yang pertama tidak-nol, tidak-kosong, tidak ada-Tidak ada yang dikembalikan dan jika tidak ada makaNone
dikembalikan apakah adaNone
atau tidak!Jadi
check_all_conditions()
fungsi saya terlihat seperti ini:Menggunakan
timeit
dengannumber=10**7
saya melihat waktu berjalan sejumlah saran. Demi perbandingan, saya hanya menggunakanrandom.random()
fungsi untuk mengembalikan string atauNone
berdasarkan angka acak. Ini seluruh kodenya:Dan inilah hasilnya:
sumber
Cara ini sedikit di luar kotak, tapi saya pikir hasil akhirnya sederhana, mudah dibaca, dan terlihat bagus.
Ide dasarnya adalah
raise
pengecualian ketika salah satu fungsi mengevaluasi sebagai kebenaran, dan mengembalikan hasilnya. Begini tampilannya:Anda akan membutuhkan
assertFalsey
fungsi yang menimbulkan pengecualian ketika salah satu dari argumen fungsi yang dipanggil mengevaluasi sebagai benar:Di atas dapat dimodifikasi sehingga juga memberikan argumen untuk fungsi yang akan dievaluasi.
Dan tentu saja Anda akan membutuhkannya
TruthyException
sendiri. Pengecualian ini memberikanobject
yang memicu pengecualian:Anda dapat mengubah fungsi asli menjadi sesuatu yang lebih umum, tentu saja:
Ini mungkin sedikit lebih lambat karena Anda menggunakan
if
pernyataan dan penanganan pengecualian. Namun, pengecualian hanya ditangani maksimal satu kali, sehingga hit ke kinerja harus kecil kecuali jika Anda berharap untuk menjalankan pemeriksaan dan mendapatkanTrue
nilai ribuan kali.sumber
StopIteration
adalah contoh yang cukup bagus: sebuah pengecualian dimunculkan setiap kali Anda menghabiskan iterable. Hal yang ingin Anda hindari adalah terus meningkatkan pengecualian, yang akan menjadi mahal. Tetapi melakukannya sekali saja tidak.Cara pythonic adalah dengan menggunakan perkecil (seperti yang telah seseorang sebutkan) atau itertools (seperti yang ditunjukkan di bawah), tetapi bagi saya tampaknya hanya dengan menggunakan korsleting dari
or
operator menghasilkan kode yang lebih jelas.sumber
Saya akan melompat ke sini dan tidak pernah menulis satu baris pun Python, tapi saya berasumsi
if x = check_something(): return x
valid?jika begitu:
sumber
if ( x := check_size() ) :
untuk efek yang sama.Atau gunakan
max
:sumber
Saya telah melihat beberapa implementasi yang menarik dari pernyataan switch / case dengan dikt di masa lalu yang mengarahkan saya ke jawaban ini. Dengan menggunakan contoh yang Anda berikan Anda akan mendapatkan yang berikut. (Ini kegilaan
using_complete_sentences_for_function_names
, jadicheck_all_conditions
berganti nama menjadistatus
. Lihat (1))Fungsi pilih menghilangkan kebutuhan untuk memanggil masing-masing
check_FUNCTION
dua kali yaitu Anda menghindaricheck_FUNCTION() if check_FUNCTION() else next
dengan menambahkan lapisan fungsi lain. Ini berguna untuk fungsi yang berjalan lama. Lambda dalam eksekusi penundaan nilai-nilai itu sampai loop sementara.Sebagai bonus, Anda dapat memodifikasi urutan eksekusi dan bahkan melewatkan beberapa tes dengan mengubah
k
dans
misalnyak='c',s={'c':'b','b':None}
mengurangi jumlah tes dan membalik urutan pemrosesan asli.Itu
timeit
orang mungkin tawar-menawar tentang biaya menambahkan satu atau dua lapisan tambahan ke tumpukan dan biaya untuk mendikte mencari tetapi Anda tampaknya lebih peduli dengan kecantikan kode.Atau implementasi yang lebih sederhana mungkin sebagai berikut:
sumber
check_no/some/even/prime/every_third/fancy_conditions
tetapi hanya fungsi yang satu ini jadi mengapa tidak menyebutnyastatus
atau jika seseorang bersikerascheck_status
. Menggunakan_all_
itu berlebihan, dia tidak memastikan integritas alam semesta. Penamaan tentu harus menggunakan set kata kunci yang konsisten yang meningkatkan spasi nama bila memungkinkan. Kalimat yang panjang paling baik dijadikan sebagai dokumen. Seseorang jarang membutuhkan lebih dari 8-10 karakter untuk menggambarkan sesuatu secara ringkas.check_all_conditions
itu nama yang buruk, karena itu tidak memeriksa semua kondisi jika ada yang benar. Saya akan menggunakan sesuatu sepertimatches_any_condition
.