Piese de schimb pentru comutator declarație în Python?

Vreau să se scrie o funcție în Python, care se întoarce diferite valori fixe pe baza valorii de intrare de index.

În alte limbi mi-ar folosi un "comutator" sau " caz "declarație, dar Python nu pare a fi un "comutator" declarație. Ce sunt recomandate Python soluții în acest scenariu?

Comentarii la întrebare (9)
Soluția

Ai putea folosi un dicționar:

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

Daca'd ca implicite ai putea folosi dicționar ia(cheie[, default]) metoda:

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

Am'am plăcut întotdeauna de a face în acest fel

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

De aici

Comentarii (15)

În plus față de dicționarul metode (care chiar imi place, BTW), puteți utiliza, de asemenea, dacă-elif-altcineva pentru a obține switch/case/default funcționalitate:

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

Aceasta, desigur, nu este identic cu switch/case - de tine nu poate fi toamna-prin fel de ușor ca și lăsând pe pauză; declarație, dar puteți avea o mult mai complicat de testare. Formatarea acestuia este mai frumos decât o serie de imbricate ifs, chiar dacă din punct de vedere funcțional, care's ceea ce este mai aproape de.

Comentarii (11)

Preferata mea Python reteta pentru comutator/caz este:

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

Scurt și simplu pentru scenarii simple.

Compara cu 11+ linii de cod C:

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

Aveți posibilitatea să atribuiți chiar de mai multe variabile, cu ajutorul tupluri:

choices = {'a': (1, 2, 3), 'b': (4, 5, 6)}
(result1, result2, result3) = choices.get(key, ('default1', 'default2', 'default3'))
Comentarii (9)
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))

Utilizare:

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

Teste:

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

Preferata mea este un foarte frumos reteta. Te'll place foarte mult. L's cel mai apropiat I'am vazut la real comutator caz de declarații, mai ales în funcții.

``python clasa de comutare(obiect): def init(self, valoare): auto.valoare = valoare auto.toamna = False

def iter(self): """se Întoarcă meciul metodă o dată, apoi opri""" randament de sine.meci ridica StopIteration

def meci(auto, *args): """Indică dacă sau nu să introduceți un caz suite""" dacă auto.se încadrează sau nu args: return True elif auto.valoarea în args: # s-a schimbat pentru v1.5, vezi mai jos auto.toamna = True return True altceva: return False ``

Aici's un exemplu:

``python

Următorul exemplu este destul de mult exact caz de utilizare a unui dicționar,

dar este inclus pentru simplitatea sa. Rețineți că puteți include declarații

în fiecare suită.

v = 'ten' pentru cazul în comutatorul(v): dacă este cazul('o'): imprimare 1 pauza dacă este cazul('doi'): imprimare 2 pauza dacă este cazul('ten'): imprimare 10 pauza dacă este cazul('unsprezece'): imprimare 11 pauza dacă este cazul(): # implicit, ar putea, de asemenea, doar omite condiție sau 'dacă este Adevărat' print "altceva!"

Nu este nevoie pentru a rupe aici, l'll stop

rup este folosit aici să se uite la fel de mult ca un lucru real posibil, dar

elif este în general la fel de bine si mai concis.

Gol suites sunt considerate erori de sintaxă, deci intenționată toamna-through

ar trebui să conțină 'trece'

c = 'z' pentru cazul în comutatorul(c): dacă este cazul('un'): trece # este necesar numai dacă restul suite este gol dacă este cazul('b'): pass

...

dacă este cazul('y'): pass dacă este cazul('z'): print "c este scris cu litere mici!" pauza dacă este cazul('Un'): pass

...

dacă este cazul('Z'): print "c este majuscule!" pauza dacă este cazul(): # default print "nu știu ce c!"

Cum a sugerat de către Pierre Quentel, se poate extinde chiar și asupra

funcționalitatea clasic 'caz' declarație de potrivire mai multe

cazuri într-o singură lovitură. Acest lucru foarte mult beneficiile operațiuni cum ar fi

majuscule/litere mici exemplul de mai sus:

import string c = 'Un' pentru cazul în comutatorul(c): dacă este cazul(string.litere mici): # notă pentru despachetare ca argumente print "c este scris cu litere mici!" pauza dacă este cazul(*string.majuscule): print "c este majuscule!" pauza daca este cazul('!', '?', '.'): # normal argument trece stil, de asemenea, se aplică print "c este o propoziție terminator!" pauza dacă este cazul(): # default print "nu știu ce c!" ``

Comentarii (5)

``python clasa de Comutare: def init(self, valoare): auto.valoare = valoare

def intre(self): reveni auto

def exit(self, tip, valoare, traceback): return False # Permite o traceback să apară

def call(self, *valori): reveni sine.valoarea în valori

din datetime import datetime

cu Comutatorul(datetime.astăzi().weekday()) după caz: dacă este cazul(0):

Utilizare de bază a comuta

de imprimare("urăsc zilele de luni atât de mult.")

Notă nu există nici o pauză nevoie de aici

elif caz(1,2):

Acest comutator sprijină, de asemenea mai multe condiții (într-o singură linie)

de imprimare("atunci Când este week-end va fi aici?") elif caz(3,4): de imprimare("week-end este aproape.") altceva:

Default-ar avea loc aici

de imprimare("Sa's distracție plăcută!") # N't caz de utilizare de exemplu scopuri ``

Comentarii (3)

Nu's un model care l-am învățat de la Twisted cod 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'

Îl puteți folosi în orice moment aveți nevoie pentru a trimite pe un semn și executa extins bucată de cod. Într-o mașină de stat ar fi state_ metode, și un dispecer de la sine.de stat. Acest comutator poate fi lesne extinsă de moșteniți din clasa de bază și definesc propriile do metode. De multe ori ai castigat't chiar trebuie do metodele din clasa de baza.

Edit: cât de exact este că used

În caz de SMTP veți primi ELICOPTER din sârmă. Codul relevant (de la twisted/mail/smtp.py`, modificate pentru cazul nostru) arata ca acest lucru

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

Te'll primi ' HELO foo.bar.com ' (sau s-ar putea obține 'QUIT' " sau " 'RCPT TO: foo'). Acest lucru este tokenized în "părți", ca['HELO', 'foo.bar.com']. Metoda actuală de căutare numele este luat de lapiese[0]`.

(Original metodă este, de asemenea, numit state_COMMAND, pentru că se folosește același model pentru a implementa o mașină de stat, adică getattr(auto, 'state_' + auto.modul de))

Comentarii (7)

Las's spun nu't doriți să se întoarcă o valoare, dar doriți să utilizați metode care modifica ceva pe un obiect. Folosind abordarea menționat aici ar fi:

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

Ce se întâmplă aici este că python evaluează toate metodele în dicționar. Deci, chiar dacă valoarea ta este 'un', obiect va primi incrementat și decrementat cu x.

Soluție:

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

result = func(*args)

Deci, veți obține o listă care conține o funcție și argumentele sale. În acest fel, numai funcția pointer și lista argument obține revenit, nu evaluate. 'rezultat' evaluează apoi a revenit funcția de apel.

Comentarii (0)

Am'm doar de gând să renunțe la cei doi cenți ai mei aici. Motivul nu e't un caz/comutator declarație în Python deoarece Python urmează principiul de 'Există doar un singur mod corect de a face ceva'. Deci, evident, ai putea veni cu moduri diferite de a recrea comutator/caz funcționalitate, dar Pythonic mod de a realiza acest lucru este în cazul în care/elif construct. ie

if something:
    return "first thing"
elif somethingelse:
    return "second thing"
elif yetanotherthing:
    return "third thing"
else:
    return "default thing"

Am simțit PEP 8 meritat un semn aici. Unul dintre lucrurile frumoase despre Python este simplitatea si eleganta. Care este în mare măsură derivate din principiile noastre în PEP 8, inclusiv "Nu's doar un singur mod corect de a face ceva"

Comentarii (8)

extinderea pe "dict ca comutator" ideea. dacă doriți să utilizați o valoare implicită pentru switch:

def f(x):
    try:
        return {
            'a': 1,
            'b': 2,
        }[x]
    except KeyError:
        return 'default'
Comentarii (2)

Dacă aveți un complicat caz de bloc puteți lua în considerare, folosind o funcție de căutare dicționar de masă...

Dacă te-ai't face acest lucru înainte de a fi o idee bună să-ți debugger și vezi exact cum dicționar arata de fiecare funcție.

NOTĂ: Nu nu utilizați "()" în cazul/dicționar de căutare sau se va apela fiecare dintre funcțiile fel de dicționar / caz de bloc este creat. Amintesc acest lucru pentru că vrei doar pentru a apela fiecare funcție o dată folosind un hash stil de căutare.

def first_case():
    print "first"

def second_case():
    print "second"

def third_case():
    print "third"

mycase = {
'first': first_case, #do not use ()
'second': second_case, #do not use ()
'third': third_case #do not use ()
}
myfunc = mycase['first']
myfunc()
Comentarii (1)

Daca're în căutarea extra-declarație, ca "comutator", am construit un modul python care se extinde Python. L's a numit ESPY ca "Îmbunătățită Structura de Python" si's disponibil pentru ambele Python 2.x și Python 3.x.

De exemplu, în acest caz, un comutator declarație ar putea fi realizată prin următorul cod:

macro switch(arg1):
    while True:
        cont=False
        val=%arg1%
        socket case(arg2):
            if val==%arg2% or cont:
                cont=True
                socket
        socket else:
            socket
        break

care pot fi utilizate astfel:

a=3
switch(a):
    case(0):
        print("Zero")
    case(1):
        print("Smaller than 2"):
        break
    else:
        print ("greater than 1")

deci espy traduce în Python ca:

a=3
while True:
    cont=False
    if a==0 or cont:
        cont=True
        print ("Zero")
    if a==1 or cont:
        cont=True
        print ("Smaller than 2")
        break
    print ("greater than 1")
    break
Comentarii (3)

Am constatat că o comună comutator structura:

switch ...parameter...
case p1: v1; break;
case p2: v2; break;
default: v3;

poate fi exprimat în Python, după cum urmează:

(lambda x: v1 if p1(x) else v2 if p2(x) else v3)

sau formatate într-un mod mai clar:

(lambda x:
     v1 if p1(x) else
     v2 if p2(x) else
     v3)

În loc de a fi o declarație, versiunea python este o expresie care se evaluează la o valoare.

Comentarii (4)

Am't găsi răspunsul simplu am fost în căutarea pentru oriunde de pe Google search. Dar mi-am dat seama oricum. L's într-adevăr destul de simplu. A decis sa-l postez si poate preveni mai puține zgârieturi pe altcineva's cap. Cheia este pur și simplu "în" și tupluri. Aici este comutator declarație de comportament cu toamna-prin, inclusiv ALEATOARE toamna-prin.

l = ['Dog', 'Cat', 'Bird', 'Bigfoot',
     'Dragonfly', 'Snake', 'Bat', 'Loch Ness Monster']

for x in l:
    if x in ('Dog', 'Cat'):
        x += " has four legs"
    elif x in ('Bat', 'Bird', 'Dragonfly'):
        x += " has wings."
    elif x in ('Snake',):
        x += " has a forked tongue."
    else:
        x += " is a big mystery by default."
    print(x)

print()

for x in range(10):
    if x in (0, 1):
        x = "Values 0 and 1 caught here."
    elif x in (2,):
        x = "Value 2 caught here."
    elif x in (3, 7, 8):
        x = "Values 3, 7, 8 caught here."
    elif x in (4, 6):
        x = "Values 4 and 6 caught here"
    else:
        x = "Values 5 and 9 caught in default."
    print(x)

Oferă:

Dog has four legs
Cat has four legs
Bird has wings.
Bigfoot is a big mystery by default.
Dragonfly has wings.
Snake has a forked tongue.
Bat has wings.
Loch Ness Monster is a big mystery by default.

Values 0 and 1 caught here.
Values 0 and 1 caught here.
Value 2 caught here.
Values 3, 7, 8 caught here.
Values 4 and 6 caught here
Values 5 and 9 caught in default.
Values 4 and 6 caught here
Values 3, 7, 8 caught here.
Values 3, 7, 8 caught here.
Values 5 and 9 caught in default.
Comentarii (5)

Cele mai multe dintre răspunsurile de aici sunt destul de vechi, și mai ales cele acceptate, astfel încât se pare că merită actualizarea.

În primul rând, oficial Python FAQ se referă la acest lucru, și recomandă elif lanț pentru cazuri simple și dict mai mari sau mai complexe cazuri. Acesta sugerează, de asemenea, un set de visit_ metode (un stil folosit de multe server cadre) pentru unele cazuri:

def dispatch(self, value):
    method_name = 'visit_' + str(value)
    method = getattr(self, method_name)
    method()

FAQ menționează, de asemenea, PEP 275, care a fost scris pentru a obține un oficial odată-și-pentru-toate deciziei privind adăugarea de C-comutator stil declarații. Dar PEP a fost, de fapt, amânată pentru Python 3, și a fost respinsă în mod oficial ca o propunere separată, PEP 3103. Răspunsul a fost, desigur, nu—dar cele două PEPs au link-uri către informații suplimentare daca're interesat de motivele sau istoria.


Un lucru care a venit de mai multe ori (și poate fi văzut în PEP 275, chiar dacă a fost tăiat ca un real recomandare) este că, dacă te're într-adevăr deranjat de a avea 8 linii de cod să se ocupe de 4 cazuri, față de cele 6 linii te'd au în C sau Bash, puteți scrie întotdeauna aceasta:

if x == 1: print('first')
elif x == 2: print('second')
elif x == 3: print('third')
else: print('did not place')

Asta e't mai exact încurajat de PEP 8, dar's ușor de citit și nu prea unidiomatic.


Peste mai mult de un deceniu de când PEP 3103 a fost respinsă, problema C-stil de caz declarații, sau chiar puțin mai puternica versiune în Go, a fost considerat mort, ori de câte ori cineva aduce pe python-idei sau -dev, au're menționate la vechea decizie.

Cu toate acestea, ideea de a completa ML-stil de potrivire de model apare la fiecare câțiva ani, în special de limbi, cum ar fi Swift și Rugina au adoptat-o. Problema este ca's greu pentru a obține mai mult utilizarea de potrivire de model fără algebrice tipuri de date. În timp ce Guido a fost simpatic la idee, nimeni nu's-a venit cu o propunere care se potrivește în Python foarte bine. (Puteți citi mea 2014 strawman pentru un exemplu.) Acest lucru ar putea schimba cu dataclass în 3.7 și unele sporadice propuneri pentru o mai puternic enum să se ocupe de suma tipuri, sau cu diverse propuneri pentru diferite tipuri de declarație-legături locale (cum ar fi PEP 3150, sau un set de propuneri discutate în prezent la idei). Dar, până acum, nu a't.

Există, de asemenea, ocazional propuneri pentru Perl 6-stil de potrivire, care este de fapt un amestec de tot, de la elif a regex pentru o singură expediere de tip comutare.

Comentarii (0)

Soluțiile eu folosesc:

O combinație de 2 dintre soluțiile postate aici, care este relativ ușor de citit și acceptă valorile implicite.

result = {
  'a': lambda x: x * 5,
  'b': lambda x: x + 7,
  'c': lambda x: x - 2
}.get(whatToUse, lambda x: x - 22)(value)

în cazul în care

.get('c', lambda x: x - 22)(23)

se uită în sus "lambda x: x - 2" în dict si foloseste-l cux=23`

.get('xxx', lambda x: x - 22)(44)

nu't găsi în dict și utilizează implicit "lambda x: x - 22" " cu " x=44.

Comentarii (0)
# simple case alternative

some_value = 5.0

# this while loop block simulates a case block

# case
while True:

    # case 1
    if some_value > 5:
        print ('Greater than five')
        break

    # case 2
    if some_value == 5:
        print ('Equal to five')
        break

    # else case 3
    print ( 'Must be less than 5')
    break
Comentarii (1)
def f(x):
    dictionary = {'a':1, 'b':2, 'c':3}
    return dictionary.get(x,'Not Found') 
##Returns the value for the letter x;returns 'Not Found' if x isn't a key in the dictionary
Comentarii (2)