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?
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
Î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.
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'))
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.
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
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!"
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!"
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!" ``
``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):
de imprimare("urăsc zilele de luni atât de mult.")
elif caz(1,2):
de imprimare("atunci Când este week-end va fi aici?") elif caz(3,4): de imprimare("week-end este aproape.") altceva:
de imprimare("Sa's distracție plăcută!") # N't caz de utilizare de exemplu scopuri ``
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 la
piese[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)
)
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.
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"
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()
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
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.
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.
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.
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 cu
x=23`
.get('xxx', lambda x: x - 22)(44)
nu't găsi în dict și utilizează implicit "lambda x: x - 22" " cu " x=44
.
# 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
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