Pertanyaan Pengganti untuk pernyataan switch dengan Python?


Saya ingin menulis fungsi dengan Python yang mengembalikan nilai tetap yang berbeda berdasarkan nilai indeks input.

Dalam bahasa lain saya akan menggunakan switch atau case pernyataan, tetapi Python tampaknya tidak memiliki switch pernyataan. Apa solusi Python yang direkomendasikan dalam skenario ini?


1440
2017-09-13 00:36


asal


Jawaban:


Anda bisa menggunakan kamus:

def f(x):
    return {
        'a': 1,
        'b': 2,
    }[x]

1125
2017-09-13 00:38



Jika Anda ingin default Anda bisa menggunakan kamus get(key[, default]) metode:

def f(x):
    return {
        'a': 1,
        'b': 2
    }.get(x, 9)    # 9 is default if x not found

1108
2017-09-19 15:45



Saya selalu suka melakukannya dengan cara ini

result = {
  'a': lambda x: x * 5,
  'b': lambda x: x + 7,
  'c': lambda x: x - 2
}[value](x)

Dari sini


293
2017-09-13 00:41



Selain metode kamus (yang saya sangat suka, BTW), Anda juga dapat menggunakan if-elif-else untuk mendapatkan fungsi switch / case / default:

if x == 'a':
    # Do the thing
elif x == 'b':
    # Do the other thing
if x in 'bc':
    # Fall-through by not using elif, but now the default case includes case 'a'!
elif x in 'xyz':
    # Do yet another thing
else:
    # Do the default

Ini tentu saja tidak identik dengan switch / case - Anda tidak dapat melakukan fall-through semudah meninggalkan break; pernyataan, tetapi Anda dapat memiliki tes yang lebih rumit. Formatnya lebih bagus daripada serangkaian ifs bersarang, meskipun secara fungsional itulah yang lebih dekat.


248
2017-09-13 01:10



Resep Python favorit saya untuk switch / case adalah:

choices = {'a': 1, 'b': 2}
result = choices.get(key, 'default')

Singkat dan sederhana untuk skenario sederhana.

Bandingkan dengan 11+ baris kode C:

// C Language version of a simple 'switch/case'.
switch( key ) 
{
    case 'a' :
        result = 1;
        break;
    case 'b' :
        result = 2;
        break;
    default :
        result = -1;
}

Anda bahkan dapat menetapkan beberapa variabel dengan menggunakan tupel:

choices = {'a': (1, 2, 3), 'b': (4, 5, 6)}
(result1, result2, result3) = choices.get(key, ('default1', 'default2', 'default3'))

122
2018-06-17 02:25



class switch(object):
    value = None
    def __new__(class_, value):
        class_.value = value
        return True

def case(*args):
    return any((arg == switch.value for arg in args))

Pemakaian:

while switch(n):
    if case(0):
        print "You typed zero."
        break
    if case(1, 4, 9):
        print "n is a perfect square."
        break
    if case(2):
        print "n is an even number."
    if case(2, 3, 5, 7):
        print "n is a prime number."
        break
    if case(6, 8):
        print "n is an even number."
        break
    print "Only single-digit numbers are allowed."
    break

Tes:

n = 2
#Result:
#n is an even number.
#n is a prime number.
n = 11
#Result:
#Only single-digit numbers are allowed.

85
2017-07-07 06:09



Ada pola yang saya pelajari dari kode Twisted Python.

class SMTP:
    def lookupMethod(self, command):
        return getattr(self, 'do_' + command.upper(), None)
    def do_HELO(self, rest):
        return 'Howdy ' + rest
    def do_QUIT(self, rest):
        return 'Bye'

SMTP().lookupMethod('HELO')('foo.bar.com') # => 'Howdy foo.bar.com'
SMTP().lookupMethod('QUIT')('') # => 'Bye'

Anda dapat menggunakannya kapan saja Anda perlu mengirimkan token dan mengeksekusi potongan kode yang diperpanjang. Dalam mesin negara Anda akan memilikinya state_ metode, dan pengiriman self.state. Saklar ini dapat diperpanjang secara bersih dengan mewarisi dari kelas dasar dan mendefinisikan kelas Anda sendiri do_ metode. Sering kali Anda bahkan tidak akan memilikinya do_ metode di kelas dasar.

Edit: bagaimana tepatnya itu digunakan

Dalam kasus SMTP Anda akan menerima HELO dari kawat. Kode yang relevan (dari twisted/mail/smtp.py, dimodifikasi untuk kasus kami) terlihat seperti ini

class SMTP:
    # ...

    def do_UNKNOWN(self, rest):
        raise NotImplementedError, 'received unknown command'

    def state_COMMAND(self, line):
        line = line.strip()
        parts = line.split(None, 1)
        if parts:
            method = self.lookupMethod(parts[0]) or self.do_UNKNOWN
            if len(parts) == 2:
                return method(parts[1])
            else:
                return method('')
        else:
            raise SyntaxError, 'bad syntax'

SMTP().state_COMMAND('   HELO   foo.bar.com  ') # => Howdy foo.bar.com

Anda akan menerima ' HELO foo.bar.com ' (atau mungkin Anda dapatkan 'QUIT' atau 'RCPT TO: foo'). Ini di-token parts sebagai ['HELO', 'foo.bar.com']. Nama pencarian metode yang sebenarnya diambil parts[0].

(Metode asli juga disebut state_COMMAND, karena menggunakan pola yang sama untuk mengimplementasikan mesin negara, yaitu getattr(self, 'state_' + self.mode))


41
2017-09-13 01:26



Yang paling saya sukai adalah yang sangat bagus resep. Anda benar-benar menyukainya. Ini adalah yang paling dekat yang pernah saya lihat dengan pernyataan tombol switch yang sebenarnya, terutama dalam fitur.

Inilah contohnya:

# The following example is pretty much the exact use-case of a dictionary,
# but is included for its simplicity. Note that you can include statements
# in each suite.
v = 'ten'
for case in switch(v):
    if case('one'):
        print 1
        break
    if case('two'):
        print 2
        break
    if case('ten'):
        print 10
        break
    if case('eleven'):
        print 11
        break
    if case(): # default, could also just omit condition or 'if True'
        print "something else!"
        # No need to break here, it'll stop anyway

# break is used here to look as much like the real thing as possible, but
# elif is generally just as good and more concise.

# Empty suites are considered syntax errors, so intentional fall-throughs
# should contain 'pass'
c = 'z'
for case in switch(c):
    if case('a'): pass # only necessary if the rest of the suite is empty
    if case('b'): pass
    # ...
    if case('y'): pass
    if case('z'):
        print "c is lowercase!"
        break
    if case('A'): pass
    # ...
    if case('Z'):
        print "c is uppercase!"
        break
    if case(): # default
        print "I dunno what c was!"

# As suggested by Pierre Quentel, you can even expand upon the
# functionality of the classic 'case' statement by matching multiple
# cases in a single shot. This greatly benefits operations such as the
# uppercase/lowercase example above:
import string
c = 'A'
for case in switch(c):
    if case(*string.lowercase): # note the * for unpacking as arguments
        print "c is lowercase!"
        break
    if case(*string.uppercase):
        print "c is uppercase!"
        break
    if case('!', '?', '.'): # normal argument passing style also applies
        print "c is a sentence terminator!"
        break
    if case(): # default
        print "I dunno what c was!"

38
2017-07-07 06:12



class Switch:
    def __init__(self, value): self._val = value
    def __enter__(self): return self
    def __exit__(self, type, value, traceback): return False # Allows traceback to occur
    def __call__(self, *mconds): return self._val in mconds

from datetime import datetime
with Switch(datetime.today().weekday()) as case:
    if case(0):
        # Basic usage of switch
        print("I hate mondays so much.")
        # Note there is no break needed here
    elif case(1,2):
        # This switch also supports multiple conditions (in one line)
        print("When is the weekend going to be here?")
    elif case(3,4): print("The weekend is near.")
    else:
        # Default would occur here
        print("Let's go have fun!") # Didn't use case for example purposes

28
2018-05-03 09:05



Katakanlah Anda tidak ingin hanya mengembalikan nilai, tetapi ingin menggunakan metode yang mengubah sesuatu pada objek. Menggunakan pendekatan yang dinyatakan di sini adalah:

result = {
  'a': obj.increment(x),
  'b': obj.decrement(x)
}.get(value, obj.default(x))

Apa yang terjadi di sini adalah python mengevaluasi semua metode dalam kamus. Jadi bahkan jika nilai Anda adalah 'a', objek akan bertambah dan dikurangi oleh x.

Larutan:

func, args = {
  'a' : (obj.increment, (x,)),
  'b' : (obj.decrement, (x,)),
}.get(value, (obj.default, (x,)))

result = func(*args)

Jadi Anda mendapatkan daftar yang berisi fungsi dan argumennya. Dengan cara ini, hanya penunjuk fungsi dan daftar argumen yang dikembalikan, tidak dievaluasi. 'hasil' kemudian mengevaluasi panggilan fungsi yang dikembalikan.


22
2017-09-30 08:31