Saya ingin menulis fungsi dengan Python yang mengembalikan nilai tetap berbeda berdasarkan nilai indeks input.
Dalam bahasa lain saya akan menggunakan pernyataan switch
atau case
, tetapi Python tampaknya tidak memiliki switch
pernyataan. Apa solusi Python yang disarankan dalam skenario ini?
python
switch-statement
Michael Schneider
sumber
sumber
switch
sebenarnya lebih "serbaguna" daripada sesuatu yang mengembalikan nilai tetap berbeda berdasarkan nilai indeks input. Ini memungkinkan berbagai potongan kode dieksekusi. Sebenarnya tidak perlu mengembalikan nilai. Saya bertanya-tanya apakah beberapa jawaban di sini adalah pengganti yang baik untukswitch
pernyataan umum , atau hanya untuk kasus pengembalian nilai tanpa kemungkinan mengeksekusi potongan kode umum.Jawaban:
Anda bisa menggunakan kamus:
sumber
get
metode ini mungkin akan lebih normal daripada menggunakancollections.defaultdict
dalam kasus ini.}.get(x, default)
sebaliknya jika harus ada default. (Catatan: ini jauh lebih baik daripada apa yang terjadi jika Anda membiarkan default dari pernyataan switch!)Jika Anda ingin default, Anda bisa menggunakan
get(key[, default])
metode kamus :sumber
Saya selalu suka melakukannya dengan cara ini
Dari sini
sumber
.get()
(seperti jawaban tertinggi saat ini) perlu dengan bersemangat mengevaluasi semua kemungkinan sebelum pengiriman, dan karena itu tidak hanya (tidak hanya sangat tetapi) sangat tidak efisien dan juga tidak dapat memiliki efek samping; jawaban ini mengatasi masalah itu, tetapi lebih bersifat verbal. Saya hanya akan menggunakan if / elif / else, dan bahkan mereka butuh waktu lama untuk menulis sebagai 'case'.[value]
, yang akan mengembalikan hanya satu dari 3 fungsi (dengan asumsivalue
adalah salah satu dari 3 kunci). Fungsi belum dipanggil pada saat itu. Kemudian(x)
panggil fungsi yang baru saja dikembalikan denganx
argumen (dan hasilnya menuju keresult
). 2 fungsi lainnya tidak akan dipanggil.Selain metode kamus (yang sangat saya sukai, BTW), Anda juga dapat menggunakan
if
-elif
-else
untuk mendapatkan fungsiswitch
/case
/default
:Ini tentu saja tidak identik dengan beralih / kasing - Anda tidak dapat terjatuh semudah meninggalkan
break
pernyataan, tetapi Anda dapat memiliki tes yang lebih rumit. Pemformatannya lebih bagus daripada serangkaian nestedif
s, meskipun secara fungsional itulah yang lebih dekat dengannya.sumber
get
cara, tetapi cara standar lebih mudah dibaca.x = the.other.thing
sebelumnya. Biasanya, Anda akan memiliki satu if, multiple elif dan single lainnya, karena itu lebih mudah dipahami.if/elif/else
?x in 'bc'
, perlu diingat bahwa"" in "bc"
iniTrue
.Resep Python favorit saya untuk sakelar / kasing adalah:
Singkat dan sederhana untuk skenario sederhana.
Bandingkan dengan 11+ baris kode C:
Anda bahkan dapat menetapkan beberapa variabel dengan menggunakan tuple:
sumber
default = -1; result = choices.get(key, default)
.result=key=='a'?1:key==b?2:-1
result = 1 if key == 'a' else (2 if key == 'b' else 'default')
. tetapi apakah satu liner dapat dibaca?Pemakaian:
Tes:
sumber
if
pernyataan standar ?case(2)
blok memanggil fungsi lain yang menggunakan switch (), maka ketika melakukancase(2, 3, 5, 7)
dll untuk mencari kasus selanjutnya yang akan dieksekusi, ia akan menggunakan nilai sakelar yang diatur oleh fungsi lain bukan yang disetel oleh pernyataan sakelar saat ini .Resep favorit saya adalah resep yang sangat enak . Anda akan sangat menyukainya. Ini yang paling dekat yang pernah saya lihat dengan pernyataan kasus sakelar aktual, terutama di fitur.
Ini sebuah contoh:
sumber
for case in switch()
denganwith switch() as case
, lebih masuk akal, karena itu perlu dijalankan hanya sekali.with
tidak memungkinkan untukbreak
, jadi opsi fallthrough diambil.if c in set(range(0,9)): print "digit" elif c in set(map(chr, range(ord('a'), ord('z')))): print "lowercase"
?sumber
value
ke kelas Switch sehingga Anda bisa referensicase.value
dalam pernyataan itu.Ada pola yang saya pelajari dari kode Twisted Python.
Anda dapat menggunakannya kapan saja Anda perlu mengirim token dan mengeksekusi sepotong kode yang diperluas. Di mesin negara Anda akan memiliki
state_
metode, dan pengirimanself.state
. Switch ini dapat diperluas dengan mewarisi dari kelas dasar dan mendefinisikando_
metode Anda sendiri . Sering kali Anda bahkan tidak akan memilikido_
metode di kelas dasar.Sunting: bagaimana tepatnya itu digunakan
Dalam hal SMTP, Anda akan menerima
HELO
dari kawat. Kode yang relevan (daritwisted/mail/smtp.py
, dimodifikasi untuk kasus kami) terlihat seperti iniAnda akan menerima
' HELO foo.bar.com '
(atau Anda mungkin mendapatkan'QUIT'
atau'RCPT TO: foo'
). Ini tokenized menjadiparts
sebagai['HELO', 'foo.bar.com']
. Nama pencarian metode yang sebenarnya diambil dariparts[0]
.(Metode asli juga disebut
state_COMMAND
, karena menggunakan pola yang sama untuk mengimplementasikan mesin negara, yaitugetattr(self, 'state_' + self.mode)
)sumber
Katakanlah Anda tidak ingin hanya mengembalikan nilai, tetapi ingin menggunakan metode yang mengubah sesuatu pada suatu objek. Menggunakan pendekatan yang dinyatakan di sini adalah:
Apa yang terjadi di sini adalah python mengevaluasi semua metode dalam kamus. Jadi, bahkan jika nilai Anda adalah 'a', objek akan bertambah dan dikurangi dengan x.
Larutan:
Jadi, Anda mendapatkan daftar yang berisi fungsi dan argumennya. Dengan cara ini, hanya pointer fungsi dan daftar argumen yang dikembalikan, tidak dievaluasi. 'result' kemudian mengevaluasi pemanggilan fungsi yang dikembalikan.
sumber
Saya hanya akan menurunkan dua sen saya di sini. Alasan tidak ada pernyataan case / switch dalam Python adalah karena Python mengikuti prinsip 'Hanya ada satu cara yang tepat untuk melakukan sesuatu'. Jadi jelas Anda bisa membuat berbagai cara untuk menciptakan fungsi switch / case, tetapi cara Pythonic untuk mencapai ini adalah if / elif construct. yaitu
Saya hanya merasa PEP 8 layak mendapat anggukan di sini. Salah satu hal indah tentang Python adalah kesederhanaan dan keanggunannya. Itu sebagian besar berasal dari prinsip-prinsip yang tercantum dalam PEP 8, termasuk "Hanya ada satu cara yang tepat untuk melakukan sesuatu"
sumber
memperluas gagasan "dict as switch". jika Anda ingin menggunakan nilai default untuk sakelar Anda:
sumber
'default'
) dari aturan (dapatkan sesuatu dari dikt ini). Secara desain, program Python menggunakan pengecualian dengan mudah. Yang sedang berkata, menggunakanget
berpotensi dapat membuat kode sedikit lebih baik.Jika Anda memiliki blok kasus yang rumit, Anda dapat mempertimbangkan menggunakan tabel pencarian kamus fungsi ...
Jika Anda belum melakukan ini sebelumnya, ide yang bagus untuk masuk ke debugger dan lihat bagaimana kamus melihat setiap fungsi.
CATATAN: Do tidak menggunakan "()" dalam kasus / kamus lookup atau akan memanggil masing-masing fungsi Anda sebagai blok kamus / kasus dibuat. Ingat ini karena Anda hanya ingin memanggil setiap fungsi sekali menggunakan pencarian gaya hash.
sumber
Jika Anda mencari pernyataan ekstra, sebagai "switch", saya membangun modul python yang memperluas Python. Ini disebut ESPY sebagai "Enhanced Structure for Python" dan tersedia untuk Python 2.x dan Python 3.x.
Misalnya, dalam hal ini, pernyataan switch dapat dilakukan dengan kode berikut:
yang bisa digunakan seperti ini:
jadi tanyalah menerjemahkannya dengan Python sebagai:
sumber
while True:
di bagian atas kode Python yang dihasilkan? Ini pasti akan mengenai bagianbreak
bawah kode Python yang dihasilkan, jadi menurut saya keduanyawhile True:
danbreak
dapat dihapus. Lebih lanjut, apakah ESPY cukup pintar untuk mengubah namacont
jika pengguna menggunakan nama yang sama dalam kode mereka sendiri? Bagaimanapun, saya ingin menggunakan vanilla Python jadi saya tidak akan menggunakan ini, tapi tidak masalah. +1 untuk kesejukan belaka.while True:
danbreak
s adalah untuk mengizinkan tetapi tidak memerlukan penerusan .Saya menemukan bahwa struktur saklar umum:
dapat diekspresikan dalam Python sebagai berikut:
atau diformat dengan cara yang lebih jelas:
Alih-alih menjadi pernyataan, versi python adalah ekspresi, yang mengevaluasi nilai.
sumber
parameter
danp1==parameter
f = lambda x: 'a' if x==0 else 'b' if x==1 else 'c'
. Ketika saya kemudian meneleponf(2)
, saya mendapat'c'
;f(1)
,'b'
; danf(0)
,'a'
. Adapun p1 (x), ini menunjukkan predikat; selama ia kembaliTrue
atauFalse
, tidak peduli itu panggilan fungsi atau ekspresi, tidak apa-apa.Sebagian besar jawaban di sini sudah cukup lama, dan terutama yang diterima, jadi sepertinya layak diperbarui.
Pertama, FAQ Python resmi membahas hal ini, dan merekomendasikan
elif
rantai untuk kasus sederhana dandict
untuk kasus yang lebih besar atau lebih kompleks. Ini juga menyarankan serangkaianvisit_
metode (gaya yang digunakan oleh banyak kerangka kerja server) untuk beberapa kasus:FAQ juga menyebutkan PEP 275 , yang ditulis untuk mendapatkan keputusan resmi sekali-untuk-semua tentang penambahan pernyataan beralih gaya-C. Tetapi PEP itu sebenarnya ditangguhkan ke Python 3, dan hanya secara resmi ditolak sebagai proposal terpisah, PEP 3103 . Jawabannya tentu saja tidak — tetapi kedua PEP memiliki tautan ke informasi tambahan jika Anda tertarik pada alasan atau sejarahnya.
Satu hal yang muncul beberapa kali (dan dapat dilihat dalam PEP 275, meskipun itu dipotong sebagai rekomendasi sebenarnya) adalah bahwa jika Anda benar-benar terganggu dengan memiliki 8 baris kode untuk menangani 4 kasus, vs. 6 baris yang Anda miliki di C atau Bash, Anda selalu dapat menulis ini:
Ini tidak sepenuhnya didorong oleh PEP 8, tetapi itu dapat dibaca dan tidak terlalu tidak otomatis.
Selama lebih dari satu dekade sejak PEP 3103 ditolak, masalah pernyataan kasus C-style, atau bahkan versi yang sedikit lebih kuat di Go, telah dianggap mati; setiap kali ada yang membawanya pada python-ideas atau -dev, mereka dirujuk ke keputusan lama.
Namun, gagasan pencocokan pola gaya ML penuh muncul setiap beberapa tahun, terutama karena bahasa seperti Swift dan Rust telah mengadopsinya. Masalahnya adalah sulit untuk menggunakan banyak dari pencocokan pola tanpa tipe data aljabar. Sementara Guido bersimpati pada ide tersebut, tidak ada yang datang dengan proposal yang cocok dengan Python. (Anda dapat membaca strawman 2014 saya sebagai contoh.) Ini bisa berubah dengan
dataclass
di 3.7 dan beberapa proposal sporadis untuk yang lebih kuatenum
untuk menangani jenis penjumlahan, atau dengan berbagai proposal untuk berbagai jenis ikatan lokal-pernyataan (seperti PEP 3150 , atau set proposal yang saat ini sedang dibahas di -ideas). Tapi sejauh ini, belum.Ada juga kadang-kadang proposal untuk pencocokan gaya 6-Perl, yang pada dasarnya merupakan mishmash dari segalanya mulai dari
elif
regex ke jenis-pengiriman tunggal-switching.sumber
Solusi untuk menjalankan fungsi:
di mana foo1 (), foo2 (), foo3 () dan default () adalah fungsi
sumber
foo2()
, fungsifoo1()
,foo3()
dandefault()
fungsi semuanya juga akan berjalan, artinya segalanya bisa memakan waktu lamaget(option)()
. masalah terpecahkan.Saya tidak menemukan jawaban sederhana yang saya cari di mana saja di pencarian Google. Tapi toh aku yang menemukannya. Ini sangat sederhana. Memutuskan untuk mempostingnya, dan mungkin mencegah goresan di kepala orang lain lebih sedikit. Kuncinya hanyalah "dalam" dan tupel. Berikut adalah perilaku pernyataan switch dengan fall-through, termasuk fall-through RANDOM.
Menyediakan:
sumber
break
di akhir kode untuk acase
. Tapi saya pikir kita tidak perlu seperti "fallthrough" :)Solusi yang saya gunakan:
Kombinasi 2 solusi yang diposting di sini, yang relatif mudah dibaca dan mendukung default.
dimana
melihat
"lambda x: x - 2"
dict dan menggunakannya denganx=23
tidak menemukannya di dict dan menggunakan default
"lambda x: x - 22"
denganx=44
.sumber
sumber
sumber
aku suka jawaban Mark Bies
Sejak
x
variabel harus digunakan dua kali, saya memodifikasi fungsi lambda menjadi parameterless.Saya harus menjalankannya
results[value](value)
Sunting: Saya perhatikan bahwa saya dapat menggunakan
None
jenis dengan kamus. Jadi ini akan ditiruswitch ; case else
sumber
result[None]()
?result = {'a': 100, None:5000}; result[None]
None:
berperilaku sepertidefault:
.Singkat dan mudah dibaca, memiliki nilai default dan mendukung ekspresi di kedua kondisi dan mengembalikan nilai.
Namun, ini kurang efisien daripada solusi dengan kamus. Misalnya, Python harus memindai semua kondisi sebelum mengembalikan nilai default.
sumber
Anda dapat menggunakan dict yang dikirim:
Keluaran:
sumber
Sederhana, tidak diuji; setiap kondisi dievaluasi secara independen: tidak ada jatuh, tetapi semua kasus dievaluasi (meskipun ekspresi untuk menghidupkan hanya dievaluasi sekali), kecuali ada pernyataan istirahat. Sebagai contoh,
cetakan
Was 1. Was 1 or 2. Was something.
(Sial! Mengapa saya tidak dapat memiliki spasi spasi di blok kode sebaris?) jikaexpression
dievaluasi1
,Was 2.
jikaexpression
dievaluasi2
, atauWas something.
jikaexpression
dievaluasi ke yang lain.sumber
Mendefinisikan:
memungkinkan Anda untuk menggunakan sintaks yang cukup mudah, dengan case yang dibundel ke dalam peta:
Saya terus mencoba mendefinisikan ulang saklar dengan cara yang akan membiarkan saya menyingkirkan "lambda:", tetapi menyerah. Tweak definisi:
Mengizinkan saya memetakan banyak kasing ke kode yang sama, dan untuk menyediakan opsi default:
Setiap case yang direplikasi harus dalam kamusnya sendiri; switch () mengkonsolidasikan kamus sebelum mencari nilainya. Ini masih lebih jelek daripada yang saya inginkan, tetapi memiliki efisiensi dasar menggunakan pencarian hash pada ekspresi, daripada loop melalui semua kunci.
sumber
Saya pikir cara terbaik adalah dengan menggunakan idiom bahasa python untuk menjaga kode Anda dapat diuji . Seperti yang ditunjukkan dalam jawaban sebelumnya, saya menggunakan kamus untuk memanfaatkan struktur dan bahasa python dan menjaga kode "case" tetap terisolasi dalam metode yang berbeda. Di bawah ini ada kelas, tetapi Anda dapat menggunakan modul, global, dan fungsi secara langsung. Kelas memiliki metode yang dapat diuji dengan isolasi . Bergantung pada kebutuhan Anda, Anda dapat bermain dengan metode dan atribut statis juga.
Dimungkinkan untuk mengambil keuntungan dari metode ini menggunakan juga kelas sebagai kunci "__choice_table". Dengan cara ini Anda dapat menghindari penyalahgunaan konten dan menjaga semua tetap bersih dan dapat diuji.
Andaikan Anda harus memroses banyak pesan atau paket dari internet atau MQ Anda. Setiap paket memiliki struktur dan kode manajemennya sendiri (dengan cara yang umum). Dengan kode di atas dimungkinkan untuk melakukan sesuatu seperti ini:
Jadi kompleksitas tidak menyebar dalam aliran kode tetapi ini diberikan dalam struktur kode .
sumber
Memperluas jawaban Greg Hewgill - Kita dapat merangkum solusi kamus menggunakan dekorator:
Ini kemudian dapat digunakan dengan
@case
-decoratorKabar baiknya adalah bahwa ini sudah dilakukan di NeoPySwitch -module. Cukup instal menggunakan pip:
sumber
Solusi yang cenderung saya gunakan yang juga menggunakan kamus adalah:
Ini memiliki keuntungan karena tidak mencoba untuk mengevaluasi fungsi setiap waktu, dan Anda hanya perlu memastikan bahwa fungsi luar mendapatkan semua informasi yang dibutuhkan fungsi dalam.
sumber
Ada banyak jawaban sejauh ini yang mengatakan, "kami tidak memiliki saklar di Python, lakukan dengan cara ini". Namun, saya ingin menunjukkan bahwa pernyataan switch itu sendiri adalah konstruksi yang mudah disalahgunakan yang dapat dan harus dihindari dalam kebanyakan kasus karena mereka mempromosikan pemrograman malas. Inti masalah:
Sekarang, Anda bisa melakukan ini dengan pernyataan switch (jika Python menawarkan satu) tetapi Anda akan membuang-buang waktu karena ada metode yang melakukan ini dengan baik. Atau mungkin, Anda memiliki sesuatu yang kurang jelas:
Namun, operasi semacam ini dapat dan harus ditangani dengan kamus karena akan lebih cepat, lebih kompleks, lebih rentan terhadap kesalahan dan lebih kompak.
Dan sebagian besar "kasus penggunaan" untuk pernyataan beralih akan jatuh ke dalam salah satu dari dua kasus ini; hanya ada sedikit alasan untuk menggunakannya jika Anda sudah memikirkan masalah Anda secara menyeluruh.
Jadi, daripada bertanya "bagaimana cara beralih di Python?", Mungkin kita harus bertanya, "mengapa saya ingin beralih di Python?" karena itu seringkali pertanyaan yang lebih menarik dan akan sering memaparkan kekurangan dalam desain apa pun yang sedang Anda bangun.
Sekarang, itu bukan untuk mengatakan bahwa switch tidak boleh digunakan juga. Mesin negara, lexer, parser, dan automata semuanya menggunakannya sampai tingkat tertentu dan, secara umum, ketika Anda mulai dari input simetris dan pergi ke output asimetris mereka dapat berguna; Anda hanya perlu memastikan bahwa Anda tidak menggunakan sakelar sebagai palu karena Anda melihat banyak paku dalam kode Anda.
sumber