Related
This question's answers are a community effort. Edit existing answers to improve this post. It is not currently accepting new answers or interactions.
I want to write a function in Python that returns different fixed values based on the value of an input index.
In other languages I would use a switch or case statement, but Python does not appear to have a switch statement. What are the recommended Python solutions in this scenario?
Python 3.10 (2021) introduced the match-case statement which provides a first-class implementation of a "switch" for Python. For example:
def f(x):
match x:
case 'a':
return 1
case 'b':
return 2
case _:
return 0 # 0 is the default case if x is not found
The match-case statement is considerably more powerful than this simple example.
The original answer below was written in 2008, before match-case was available:
You could use a dictionary:
def f(x):
return {
'a': 1,
'b': 2,
}[x]
If you'd like defaults, you could use the dictionary get(key[, default]) function:
def f(x):
return {
'a': 1,
'b': 2
}.get(x, 9) # 9 will be returned default if x is not found
I've always liked doing it this way
result = {
'a': lambda x: x * 5,
'b': lambda x: x + 7,
'c': lambda x: x - 2
}[value](x)
From here
In addition to the dictionary methods (which I really like, BTW), you can also use if-elif-else to obtain the switch/case/default functionality:
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
This of course is not identical to switch/case - you cannot have fall-through as easily as leaving off the break statement, but you can have a more complicated test. Its formatting is nicer than a series of nested ifs, even though functionally that's what it is closer to.
Python >= 3.10
Wow, Python 3.10+ now has a match/case syntax which is like switch/case and more!
PEP 634 -- Structural Pattern Matching
Selected features of match/case
1 - Match values:
Matching values is similar to a simple switch/case in another language:
match something:
case 1 | 2 | 3:
# Match 1-3.
case _:
# Anything else.
#
# Match will throw an error if this is omitted
# and it doesn't match any of the other patterns.
2 - Match structural patterns:
match something:
case str() | bytes():
# Match a string like object.
case [str(), int()]:
# Match a `str` and an `int` sequence
# (`list` or a `tuple` but not a `set` or an iterator).
case [_, _]:
# Match a sequence of 2 variables.
# To prevent a common mistake, sequence patterns don’t match strings.
case {"bandwidth": 100, "latency": 300}:
# Match this dict. Extra keys are ignored.
3 - Capture variables
Parse an object; saving it as variables:
match something:
case [name, count]
# Match a sequence of any two objects and parse them into the two variables.
case [x, y, *rest]:
# Match a sequence of two or more objects,
# binding object #3 and on into the rest variable.
case bytes() | str() as text:
# Match any string like object and save it to the text variable.
Capture variables can be useful when parsing data (such as JSON or HTML) that may come in one of a number of different patterns.
Capture variables is a feature. But it also means that you need to use dotted constants (ex: COLOR.RED) only. Otherwise, the constant will be treated as a capture variable and overwritten.
More sample usage:
match something:
case 0 | 1 | 2:
# Matches 0, 1 or 2 (value).
print("Small number")
case [] | [_]:
# Matches an empty or single value sequence (structure).
# Matches lists and tuples but not sets.
print("A short sequence")
case str() | bytes():
# Something of `str` or `bytes` type (data type).
print("Something string-like")
case _:
# Anything not matched by the above.
print("Something else")
Python <= 3.9
My favorite Python recipe for switch/case was:
choices = {'a': 1, 'b': 2}
result = choices.get(key, 'default')
Short and simple for simple scenarios.
Compare to 11+ lines of C code:
// C Language version of a simple 'switch/case'.
switch( key )
{
case 'a' :
result = 1;
break;
case 'b' :
result = 2;
break;
default :
result = -1;
}
You can even assign multiple variables by using tuples:
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))
Usage:
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
Tests:
n = 2
#Result:
#n is an even number.
#n is a prime number.
n = 11
#Result:
#Only single-digit numbers are allowed.
My favorite one is a really nice recipe. It's the closest one I've seen to actual switch case statements, especially in features.
class switch(object):
def __init__(self, value):
self.value = value
self.fall = False
def __iter__(self):
"""Return the match method once, then stop"""
yield self.match
raise StopIteration
def match(self, *args):
"""Indicate whether or not to enter a case suite"""
if self.fall or not args:
return True
elif self.value in args: # changed for v1.5, see below
self.fall = True
return True
else:
return False
Here's an example:
# 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!"
Some of the comments indicated that a context manager solution using with foo as case rather than for case in foo might be cleaner, and for large switch statements the linear rather than quadratic behavior might be a nice touch. Part of the value in this answer with a for loop is the ability to have breaks and fallthrough, and if we're willing to play with our choice of keywords a little bit we can get that in a context manager too:
class Switch:
def __init__(self, value):
self.value = value
self._entered = False
self._broken = False
self._prev = None
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
return False # Allows a traceback to occur
def __call__(self, *values):
if self._broken:
return False
if not self._entered:
if values and self.value not in values:
return False
self._entered, self._prev = True, values
return True
if self._prev is None:
self._prev = values
return True
if self._prev != values:
self._broken = True
return False
if self._prev == values:
self._prev = None
return False
#property
def default(self):
return self()
Here's an example:
# Prints 'bar' then 'baz'.
with Switch(2) as case:
while case(0):
print('foo')
while case(1, 2, 3):
print('bar')
while case(4, 5):
print('baz')
break
while case.default:
print('default')
break
class Switch:
def __init__(self, value):
self.value = value
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
return False # Allows a traceback to occur
def __call__(self, *values):
return self.value in values
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
There's a pattern that I learned from Twisted Python code.
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'
You can use it any time you need to dispatch on a token and execute extended piece of code. In a state machine you would have state_ methods, and dispatch on self.state. This switch can be cleanly extended by inheriting from base class and defining your own do_ methods. Often times you won't even have do_ methods in the base class.
Edit: how exactly is that used
In case of SMTP you will receive HELO from the wire. The relevant code (from twisted/mail/smtp.py, modified for our case) looks like this
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
You'll receive ' HELO foo.bar.com ' (or you might get 'QUIT' or 'RCPT TO: foo'). This is tokenized into parts as ['HELO', 'foo.bar.com']. The actual method lookup name is taken from parts[0].
(The original method is also called state_COMMAND, because it uses the same pattern to implement a state machine, i.e. getattr(self, 'state_' + self.mode))
I'm just going to drop my two cents in here. The reason there isn't a case/switch statement in Python is because Python follows the principle of "there's only one right way to do something". So obviously you could come up with various ways of recreating switch/case functionality, but the Pythonic way of accomplishing this is the if/elif construct. I.e.,
if something:
return "first thing"
elif somethingelse:
return "second thing"
elif yetanotherthing:
return "third thing"
else:
return "default thing"
I just felt PEP 8 deserved a nod here. One of the beautiful things about Python is its simplicity and elegance. That is largely derived from principles laid out in PEP 8, including "There's only one right way to do something."
Let's say you don't want to just return a value, but want to use methods that change something on an object. Using the approach stated here would be:
result = {
'a': obj.increment(x),
'b': obj.decrement(x)
}.get(value, obj.default(x))
Here Python evaluates all methods in the dictionary.
So even if your value is 'a', the object will get incremented and decremented by x.
Solution:
func, args = {
'a' : (obj.increment, (x,)),
'b' : (obj.decrement, (x,)),
}.get(value, (obj.default, (x,)))
result = func(*args)
So you get a list containing a function and its arguments. This way, only the function pointer and the argument list get returned, not evaluated. 'result' then evaluates the returned function call.
Solution to run functions:
result = {
'case1': foo1,
'case2': foo2,
'case3': foo3,
}.get(option)(parameters_optional)
where foo1(), foo2() and foo3() are functions
Example 1 (with parameters):
option = number['type']
result = {
'number': value_of_int, # result = value_of_int(number['value'])
'text': value_of_text, # result = value_of_text(number['value'])
'binary': value_of_bin, # result = value_of_bin(number['value'])
}.get(option)(value['value'])
Example 2 (no parameters):
option = number['type']
result = {
'number': func_for_number, # result = func_for_number()
'text': func_for_text, # result = func_for_text()
'binary': func_for_bin, # result = func_for_bin()
}.get(option)()
Example 4 (only values):
option = number['type']
result = {
'number': lambda: 10, # result = 10
'text': lambda: 'ten', # result = 'ten'
'binary': lambda: 0b101111, # result = 47
}.get(option)()
If you have a complicated case block you can consider using a function dictionary lookup table...
If you haven't done this before it's a good idea to step into your debugger and view exactly how the dictionary looks up each function.
NOTE: Do not use "()" inside the case/dictionary lookup or it will call each of your functions as the dictionary / case block is created. Remember this because you only want to call each function once using a hash style lookup.
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()
If you're searching extra-statement, as "switch", I built a Python module that extends Python. It's called ESPY as "Enhanced Structure for Python" and it's available for both Python 2.x and Python 3.x.
For example, in this case, a switch statement could be performed by the following code:
macro switch(arg1):
while True:
cont=False
val=%arg1%
socket case(arg2):
if val==%arg2% or cont:
cont=True
socket
socket else:
socket
break
That can be used like this:
a=3
switch(a):
case(0):
print("Zero")
case(1):
print("Smaller than 2"):
break
else:
print ("greater than 1")
So espy translate it in Python as:
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
Most of the answers here are pretty old, and especially the accepted ones, so it seems worth updating.
First, the official Python FAQ covers this, and recommends the elif chain for simple cases and the dict for larger or more complex cases. It also suggests a set of visit_ methods (a style used by many server frameworks) for some cases:
def dispatch(self, value):
method_name = 'visit_' + str(value)
method = getattr(self, method_name)
method()
The FAQ also mentions PEP 275, which was written to get an official once-and-for-all decision on adding C-style switch statements. But that PEP was actually deferred to Python 3, and it was only officially rejected as a separate proposal, PEP 3103. The answer was, of course, no—but the two PEPs have links to additional information if you're interested in the reasons or the history.
One thing that came up multiple times (and can be seen in PEP 275, even though it was cut out as an actual recommendation) is that if you're really bothered by having 8 lines of code to handle 4 cases, vs. the 6 lines you'd have in C or Bash, you can always write this:
if x == 1: print('first')
elif x == 2: print('second')
elif x == 3: print('third')
else: print('did not place')
This isn't exactly encouraged by PEP 8, but it's readable and not too unidiomatic.
Over the more than a decade since PEP 3103 was rejected, the issue of C-style case statements, or even the slightly more powerful version in Go, has been considered dead; whenever anyone brings it up on python-ideas or -dev, they're referred to the old decision.
However, the idea of full ML-style pattern matching arises every few years, especially since languages like Swift and Rust have adopted it. The problem is that it's hard to get much use out of pattern matching without algebraic data types. While Guido has been sympathetic to the idea, nobody's come up with a proposal that fits into Python very well. (You can read my 2014 strawman for an example.) This could change with dataclass in 3.7 and some sporadic proposals for a more powerful enum to handle sum types, or with various proposals for different kinds of statement-local bindings (like PEP 3150, or the set of proposals currently being discussed on -ideas). But so far, it hasn't.
There are also occasionally proposals for Perl 6-style matching, which is basically a mishmash of everything from elif to regex to single-dispatch type-switching.
Expanding on the "dict as switch" idea. If you want to use a default value for your switch:
def f(x):
try:
return {
'a': 1,
'b': 2,
}[x]
except KeyError:
return 'default'
I found that a common switch structure:
switch ...parameter...
case p1: v1; break;
case p2: v2; break;
default: v3;
can be expressed in Python as follows:
(lambda x: v1 if p1(x) else v2 if p2(x) else v3)
or formatted in a clearer way:
(lambda x:
v1 if p1(x) else
v2 if p2(x) else
v3)
Instead of being a statement, the Python version is an expression, which evaluates to a value.
The solutions I use:
A combination of 2 of the solutions posted here, which is relatively easy to read and supports defaults.
result = {
'a': lambda x: x * 5,
'b': lambda x: x + 7,
'c': lambda x: x - 2
}.get(whatToUse, lambda x: x - 22)(value)
where
.get('c', lambda x: x - 22)(23)
looks up "lambda x: x - 2" in the dict and uses it with x=23
.get('xxx', lambda x: x - 22)(44)
doesn't find it in the dict and uses the default "lambda x: x - 22" with x=44.
You can use a dispatched dict:
#!/usr/bin/env python
def case1():
print("This is case 1")
def case2():
print("This is case 2")
def case3():
print("This is case 3")
token_dict = {
"case1" : case1,
"case2" : case2,
"case3" : case3,
}
def main():
cases = ("case1", "case3", "case2", "case1")
for case in cases:
token_dict[case]()
if __name__ == '__main__':
main()
Output:
This is case 1
This is case 3
This is case 2
This is case 1
I didn't find the simple answer I was looking for anywhere on Google search. But I figured it out anyway. It's really quite simple. Decided to post it, and maybe prevent a few less scratches on someone else's head. The key is simply "in" and tuples. Here is the switch statement behavior with fall-through, including RANDOM fall-through.
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)
Provides:
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.
# 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
I was quite confused after reading the accepted answer, but this cleared it all up:
def numbers_to_strings(argument):
switcher = {
0: "zero",
1: "one",
2: "two",
}
return switcher.get(argument, "nothing")
This code is analogous to:
function(argument){
switch(argument) {
case 0:
return "zero";
case 1:
return "one";
case 2:
return "two";
default:
return "nothing";
}
}
Check the Source for more about dictionary mapping to functions.
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
I liked Mark Bies's answer
Since the x variable must used twice, I modified the lambda functions to parameterless.
I have to run with results[value](value)
In [2]: result = {
...: 'a': lambda x: 'A',
...: 'b': lambda x: 'B',
...: 'c': lambda x: 'C'
...: }
...: result['a']('a')
...:
Out[2]: 'A'
In [3]: result = {
...: 'a': lambda : 'A',
...: 'b': lambda : 'B',
...: 'c': lambda : 'C',
...: None: lambda : 'Nothing else matters'
...: }
...: result['a']()
...:
Out[3]: 'A'
Edit: I noticed that I can use None type with with dictionaries. So this would emulate switch ; case else
def f(x):
return 1 if x == 'a' else\
2 if x in 'bcd' else\
0 #default
Short and easy to read, has a default value and supports expressions in both conditions and return values.
However, it is less efficient than the solution with a dictionary. For example, Python has to scan through all the conditions before returning the default value.
Simple, not tested; each condition is evaluated independently: there is no fall-through, but all cases are evaluated (although the expression to switch on is only evaluated once), unless there is a break statement. For example,
for case in [expression]:
if case == 1:
print(end='Was 1. ')
if case == 2:
print(end='Was 2. ')
break
if case in (1, 2):
print(end='Was 1 or 2. ')
print(end='Was something. ')
prints Was 1. Was 1 or 2. Was something. (Dammit! Why can't I have trailing whitespace in inline code blocks?) if expression evaluates to 1, Was 2. if expression evaluates to 2, or Was something. if expression evaluates to something else.
There have been a lot of answers so far that have said, "we don't have a switch in Python, do it this way". However, I would like to point out that the switch statement itself is an easily-abused construct that can and should be avoided in most cases because they promote lazy programming. Case in point:
def ToUpper(lcChar):
if (lcChar == 'a' or lcChar == 'A'):
return 'A'
elif (lcChar == 'b' or lcChar == 'B'):
return 'B'
...
elif (lcChar == 'z' or lcChar == 'Z'):
return 'Z'
else:
return None # or something
Now, you could do this with a switch-statement (if Python offered one) but you'd be wasting your time because there are methods that do this just fine. Or maybe, you have something less obvious:
def ConvertToReason(code):
if (code == 200):
return 'Okay'
elif (code == 400):
return 'Bad Request'
elif (code == 404):
return 'Not Found'
else:
return None
However, this sort of operation can and should be handled with a dictionary because it will be faster, less complex, less prone to error and more compact.
And the vast majority of "use cases" for switch statements will fall into one of these two cases; there's just very little reason to use one if you've thought about your problem thoroughly.
So, rather than asking "how do I switch in Python?", perhaps we should ask, "why do I want to switch in Python?" because that's often the more interesting question and will often expose flaws in the design of whatever you're building.
Now, that isn't to say that switches should never be used either. State machines, lexers, parsers and automata all use them to some degree and, in general, when you start from a symmetrical input and go to an asymmetrical output they can be useful; you just need to make sure that you don't use the switch as a hammer because you see a bunch of nails in your code.
A solution I tend to use which also makes use of dictionaries is:
def decision_time( key, *args, **kwargs):
def action1()
"""This function is a closure - and has access to all the arguments"""
pass
def action2()
"""This function is a closure - and has access to all the arguments"""
pass
def action3()
"""This function is a closure - and has access to all the arguments"""
pass
return {1:action1, 2:action2, 3:action3}.get(key,default)()
This has the advantage that it doesn't try to evaluate the functions every time, and you just have to ensure that the outer function gets all the information that the inner functions need.
Defining:
def switch1(value, options):
if value in options:
options[value]()
allows you to use a fairly straightforward syntax, with the cases bundled into a map:
def sample1(x):
local = 'betty'
switch1(x, {
'a': lambda: print("hello"),
'b': lambda: (
print("goodbye," + local),
print("!")),
})
I kept trying to redefine switch in a way that would let me get rid of the "lambda:", but gave up. Tweaking the definition:
def switch(value, *maps):
options = {}
for m in maps:
options.update(m)
if value in options:
options[value]()
elif None in options:
options[None]()
Allowed me to map multiple cases to the same code, and to supply a default option:
def sample(x):
switch(x, {
_: lambda: print("other")
for _ in 'cdef'
}, {
'a': lambda: print("hello"),
'b': lambda: (
print("goodbye,"),
print("!")),
None: lambda: print("I dunno")
})
Each replicated case has to be in its own dictionary; switch() consolidates the dictionaries before looking up the value. It's still uglier than I'd like, but it has the basic efficiency of using a hashed lookup on the expression, rather than a loop through all the keys.
Expanding on Greg Hewgill's answer - We can encapsulate the dictionary-solution using a decorator:
def case(callable):
"""switch-case decorator"""
class case_class(object):
def __init__(self, *args, **kwargs):
self.args = args
self.kwargs = kwargs
def do_call(self):
return callable(*self.args, **self.kwargs)
return case_class
def switch(key, cases, default=None):
"""switch-statement"""
ret = None
try:
ret = case[key].do_call()
except KeyError:
if default:
ret = default.do_call()
finally:
return ret
This can then be used with the #case-decorator
#case
def case_1(arg1):
print 'case_1: ', arg1
#case
def case_2(arg1, arg2):
print 'case_2'
return arg1, arg2
#case
def default_case(arg1, arg2, arg3):
print 'default_case: ', arg1, arg2, arg3
ret = switch(somearg, {
1: case_1('somestring'),
2: case_2(13, 42)
}, default_case(123, 'astring', 3.14))
print ret
The good news are that this has already been done in NeoPySwitch-module. Simply install using pip:
pip install NeoPySwitch
I am creating a custom 3D space from scratch for some new coders, and I am worried that perhaps my documentation isn't beginner friendly. Here is an example:
def make_point(**kwargs):
X, Y, Z = 0, 0, 0;
if "Xcoord" in kwargs.keys(): X = kwargs["Xcoord"];
if "Ycoord" in kwargs.keys(): Y = kwargs["Ycoord"];
if "Zcoord" in kwargs.keys(): Z = kwargs["Zcoord"];
return tuple(X, Y, Z);
But the way I named the keyword arguments isn't very suitable for a new programmer with some knowledge in linear algebra, but it is necessary for me to keep track which variable is what. So in that manner I have vXcoord for the vector x coordinate, pXcoord for point, etc.
Is there a way to make keyword arguments more user friendly so if a user typed vX,vectorX or whatever it seems more logical it would still map to vXcoord?
The idea:
The idea is that every class could have a list of aliases to specific attributes so user could (based on class name logic: > point needs x, y, z, name attributes, dog needs breed, name, age, sex attributes and so on) based on its own internal logic to call attributes without need for knowing exactly what attribute name sed attribute have.
The logic:
If function or class has for input some keyword arguments, then I would need minimal list of common words associated with sed argument. Synonyms and idioms can be googled easily, but I would advise against the big list of synonyms, keep it small 2-3 + attribute name. Then all we need is to map those aliases to the original attribute since we as codes need to know how to call attribute without calling getattr(self, someattributestring)
Code:
Chronologically we must first define a function to generate aliases.
# Generate aliases for attributes
def generateAliases(*argListNames):
returningValues = [] # This could be omitted if the user wants to make a generator
la = returningValues.append # This could be omitted also
# Dominated argListNames
argListNames = map(str, argListNames) # For simplicity convert to strings
argListNames = map(str.lower, argListNames) # For simplicity convert to lower string
argListNames = list(argListNames) # Back to 'list'
# Small nameless lambda functions
getFirstChr = lambda element: element[0] # Getting first character
conectedJoing = lambda connector, item, args: connecter.join([ item, args if not __isTL__(args) else connecter.join(args) ]) # Generating joined string
# List of string convertors used to generate aliases
convertorList = [ lambda x: x, getFirstChr, str.title, str.upper, lambda x: getFirstChr(str.upper(x)) ]
for item in argListNames:
## Since we don't want an alias to repeat itself
listNoitem = filter(lambda x: x != item, argListNames)
listNoitem = list(listNoitem)
la(item) # If returningValues omitted, use the 'yield' statement
for conversion in convertorList: # #1 keeping up with for loops
converted = conversion(item)
for connecter in "_, ".split(","):
for listItem in listNoitem:
for cnvrt in convertorList: # #2 cnvrt is converted second stage: used to convert the whole list of items without the current alias
cList = cnvrt(listItem)
la(conectedJoing(connecter, converted, cList)) # If returningValues is omitted, use the 'yield' statement
la(conectedJoing(connecter, converted, listNoitem)) # if returningValues is omitted, use the 'yield' statement
# If the user wanted to make a generator, omit the next lines
returningValues = [ x.replace("_", "") if x.endswith("_") else x for x in returningValues ]
returningValues = sorted(set(returningValues))
return list(map(str, returningValues))
Now we need to map and check those arguments inside a function or class, so we need some argument parser.
## **kwargs argument parser, no error
def argumentParser(ApprovedSequence, **kwargs):
# ApprovedSequence is supposed to be a dictionary data type with {"original argument": generateAliases(originalArgumentName, somealias, somealias, ...)
"""
Phrases the keyword arguments,
for example: argumentParser(ApprovedSequence, someArgument=somevalue, otherArgument=othervalue ...)
Then it checks if someArgument is needed by checking in ApprovedSequence if name "someArgument" is found in the sequence:
If "someArgument" is found in ApprovedSequence, it stores returns the dictionary of DefaultKeys: Values,
for example: DefaultKey for someArgument: somevalue
input:
argumentParser(dict: ApprovedSequence, kwargs)
returns:
dictionary of found attributes and their values
!!important!! kwargs are not case sensitive in this case, so go crazy as long as you get the appropriate keyword!!
If you don't know what kind of keywords are needed for class,
just type className.errorAttributeNames().
For example, point.errorAttributeNames()
"""
if isinstance(ApprovedSequence, dict):
di = dict.items # dictionary.values(someDict)
dk = dict.keys # dictionary.keys(someDict)
# Managing the kwargs and approved sequence data
toLowerStr = lambda el: str(el).lower() # Conversion to lower string
asingKey = lambda el: [ key for key in dk(ApprovedSequence) if toLowerStr(el) in ApprovedSequence[key] ][0] # Assigning key
return { asingKey(k):v for k,v in di(kwargs) } # Dictionary comprehension
else:
raise TypeError("argumentPhraser function accepts only a dictionary for a ApprovedSequence, aka first item")
return None
Implementation
def somefunction(**kwargs):
aliases = {
"val1": generateAliases("first", "1"),
"val2": generateAliases("second", "2")
}
approved = argumentParser(aliases, **kwargs)
if "val1" in approved.keys(): val1 = approved["val1"]
else: val1 = 0 # Setting default value for val1
if "val2" in approved.keys(): val2 = approved["val2"]
else: val2 = 1 # Setting default value for val2
# Do something or your code here
return val1, val2
# For testing purposes
for x in [ {"first": 1}, {"second": 2, "first": 3}, {"f1": 4, "s2": 5}, {"f_1": 6, "2_s": 7} ]:
# Displaying inputed variables
form = ["passed "]
form += [ "{} as {} ".format(key, value) for key, value in x.items() ]
# Implementing somefunction
print("".join(form), somefunction(**x))
Output
python27 -m kwtest
Process started >>>
passed first as 1 (1, 1)
passed second as 2 first as 3 (3, 2)
passed f1 as 4 s2 as 5 (4, 5)
passed 2_s as 7 f_1 as 6 (6, 7)
<<< Process finished. (Exit code 0)
python35 -m kwtest
Process started >>>
passed first as 1 (1, 1)
passed first as 3 second as 2 (3, 2)
passed f1 as 4 s2 as 5 (4, 5)
passed f_1 as 6 2_s as 7 (6, 7)
<<< Process finished. (Exit code 0)
If implemented in classes, the process is similar in __init__, but __getitem__, __setitem__, and __delitem__ must be coded so they could search for attribute names in aliases as well. Also, attribute names could be generated with self.attributes = list(aliases.keys()) or something like that. Default values could be stored in classes with __kwdefaults__ or 'defaults' depending on what kind of data your function is using.
This code has been tested on Python 2.7 and Python 3.5 as you can see.
Further explanation if needed
You can define aliases within class global attributes or within __init__.
Explaining further __getitem__:
def __getitem__(self, item):
if item in self.aliases.keys():
return getattr(self, item)
if any(item in value for value in self.aliases.values()):
item = [ key for key in self.aliases.keys() if item in self.aliases[key] ] [0]
return getattr(self, item)
if item in range(len(self.aliases.keys())):
item = list(self.aliases.keys())[item]
return getattr(self, item)
Explaining further __setitem__:
def __setitem__(self, item, value):
item = self.__getitem__(self, item)
# ? must have a `__dict__` method or the class needs to be instanced from an object, like class someclass(object)
item = [ key for key in vars(self).items() if self[key] == item] [0]
if item != None:
setattr(self, item, value)
This question's answers are a community effort. Edit existing answers to improve this post. It is not currently accepting new answers or interactions.
I want to write a function in Python that returns different fixed values based on the value of an input index.
In other languages I would use a switch or case statement, but Python does not appear to have a switch statement. What are the recommended Python solutions in this scenario?
Python 3.10 (2021) introduced the match-case statement which provides a first-class implementation of a "switch" for Python. For example:
def f(x):
match x:
case 'a':
return 1
case 'b':
return 2
case _:
return 0 # 0 is the default case if x is not found
The match-case statement is considerably more powerful than this simple example.
The original answer below was written in 2008, before match-case was available:
You could use a dictionary:
def f(x):
return {
'a': 1,
'b': 2,
}[x]
If you'd like defaults, you could use the dictionary get(key[, default]) function:
def f(x):
return {
'a': 1,
'b': 2
}.get(x, 9) # 9 will be returned default if x is not found
I've always liked doing it this way
result = {
'a': lambda x: x * 5,
'b': lambda x: x + 7,
'c': lambda x: x - 2
}[value](x)
From here
In addition to the dictionary methods (which I really like, BTW), you can also use if-elif-else to obtain the switch/case/default functionality:
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
This of course is not identical to switch/case - you cannot have fall-through as easily as leaving off the break statement, but you can have a more complicated test. Its formatting is nicer than a series of nested ifs, even though functionally that's what it is closer to.
Python >= 3.10
Wow, Python 3.10+ now has a match/case syntax which is like switch/case and more!
PEP 634 -- Structural Pattern Matching
Selected features of match/case
1 - Match values:
Matching values is similar to a simple switch/case in another language:
match something:
case 1 | 2 | 3:
# Match 1-3.
case _:
# Anything else.
#
# Match will throw an error if this is omitted
# and it doesn't match any of the other patterns.
2 - Match structural patterns:
match something:
case str() | bytes():
# Match a string like object.
case [str(), int()]:
# Match a `str` and an `int` sequence
# (`list` or a `tuple` but not a `set` or an iterator).
case [_, _]:
# Match a sequence of 2 variables.
# To prevent a common mistake, sequence patterns don’t match strings.
case {"bandwidth": 100, "latency": 300}:
# Match this dict. Extra keys are ignored.
3 - Capture variables
Parse an object; saving it as variables:
match something:
case [name, count]
# Match a sequence of any two objects and parse them into the two variables.
case [x, y, *rest]:
# Match a sequence of two or more objects,
# binding object #3 and on into the rest variable.
case bytes() | str() as text:
# Match any string like object and save it to the text variable.
Capture variables can be useful when parsing data (such as JSON or HTML) that may come in one of a number of different patterns.
Capture variables is a feature. But it also means that you need to use dotted constants (ex: COLOR.RED) only. Otherwise, the constant will be treated as a capture variable and overwritten.
More sample usage:
match something:
case 0 | 1 | 2:
# Matches 0, 1 or 2 (value).
print("Small number")
case [] | [_]:
# Matches an empty or single value sequence (structure).
# Matches lists and tuples but not sets.
print("A short sequence")
case str() | bytes():
# Something of `str` or `bytes` type (data type).
print("Something string-like")
case _:
# Anything not matched by the above.
print("Something else")
Python <= 3.9
My favorite Python recipe for switch/case was:
choices = {'a': 1, 'b': 2}
result = choices.get(key, 'default')
Short and simple for simple scenarios.
Compare to 11+ lines of C code:
// C Language version of a simple 'switch/case'.
switch( key )
{
case 'a' :
result = 1;
break;
case 'b' :
result = 2;
break;
default :
result = -1;
}
You can even assign multiple variables by using tuples:
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))
Usage:
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
Tests:
n = 2
#Result:
#n is an even number.
#n is a prime number.
n = 11
#Result:
#Only single-digit numbers are allowed.
My favorite one is a really nice recipe. It's the closest one I've seen to actual switch case statements, especially in features.
class switch(object):
def __init__(self, value):
self.value = value
self.fall = False
def __iter__(self):
"""Return the match method once, then stop"""
yield self.match
raise StopIteration
def match(self, *args):
"""Indicate whether or not to enter a case suite"""
if self.fall or not args:
return True
elif self.value in args: # changed for v1.5, see below
self.fall = True
return True
else:
return False
Here's an example:
# 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!"
Some of the comments indicated that a context manager solution using with foo as case rather than for case in foo might be cleaner, and for large switch statements the linear rather than quadratic behavior might be a nice touch. Part of the value in this answer with a for loop is the ability to have breaks and fallthrough, and if we're willing to play with our choice of keywords a little bit we can get that in a context manager too:
class Switch:
def __init__(self, value):
self.value = value
self._entered = False
self._broken = False
self._prev = None
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
return False # Allows a traceback to occur
def __call__(self, *values):
if self._broken:
return False
if not self._entered:
if values and self.value not in values:
return False
self._entered, self._prev = True, values
return True
if self._prev is None:
self._prev = values
return True
if self._prev != values:
self._broken = True
return False
if self._prev == values:
self._prev = None
return False
#property
def default(self):
return self()
Here's an example:
# Prints 'bar' then 'baz'.
with Switch(2) as case:
while case(0):
print('foo')
while case(1, 2, 3):
print('bar')
while case(4, 5):
print('baz')
break
while case.default:
print('default')
break
class Switch:
def __init__(self, value):
self.value = value
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
return False # Allows a traceback to occur
def __call__(self, *values):
return self.value in values
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
There's a pattern that I learned from Twisted Python code.
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'
You can use it any time you need to dispatch on a token and execute extended piece of code. In a state machine you would have state_ methods, and dispatch on self.state. This switch can be cleanly extended by inheriting from base class and defining your own do_ methods. Often times you won't even have do_ methods in the base class.
Edit: how exactly is that used
In case of SMTP you will receive HELO from the wire. The relevant code (from twisted/mail/smtp.py, modified for our case) looks like this
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
You'll receive ' HELO foo.bar.com ' (or you might get 'QUIT' or 'RCPT TO: foo'). This is tokenized into parts as ['HELO', 'foo.bar.com']. The actual method lookup name is taken from parts[0].
(The original method is also called state_COMMAND, because it uses the same pattern to implement a state machine, i.e. getattr(self, 'state_' + self.mode))
I'm just going to drop my two cents in here. The reason there isn't a case/switch statement in Python is because Python follows the principle of "there's only one right way to do something". So obviously you could come up with various ways of recreating switch/case functionality, but the Pythonic way of accomplishing this is the if/elif construct. I.e.,
if something:
return "first thing"
elif somethingelse:
return "second thing"
elif yetanotherthing:
return "third thing"
else:
return "default thing"
I just felt PEP 8 deserved a nod here. One of the beautiful things about Python is its simplicity and elegance. That is largely derived from principles laid out in PEP 8, including "There's only one right way to do something."
Let's say you don't want to just return a value, but want to use methods that change something on an object. Using the approach stated here would be:
result = {
'a': obj.increment(x),
'b': obj.decrement(x)
}.get(value, obj.default(x))
Here Python evaluates all methods in the dictionary.
So even if your value is 'a', the object will get incremented and decremented by x.
Solution:
func, args = {
'a' : (obj.increment, (x,)),
'b' : (obj.decrement, (x,)),
}.get(value, (obj.default, (x,)))
result = func(*args)
So you get a list containing a function and its arguments. This way, only the function pointer and the argument list get returned, not evaluated. 'result' then evaluates the returned function call.
Solution to run functions:
result = {
'case1': foo1,
'case2': foo2,
'case3': foo3,
}.get(option)(parameters_optional)
where foo1(), foo2() and foo3() are functions
Example 1 (with parameters):
option = number['type']
result = {
'number': value_of_int, # result = value_of_int(number['value'])
'text': value_of_text, # result = value_of_text(number['value'])
'binary': value_of_bin, # result = value_of_bin(number['value'])
}.get(option)(value['value'])
Example 2 (no parameters):
option = number['type']
result = {
'number': func_for_number, # result = func_for_number()
'text': func_for_text, # result = func_for_text()
'binary': func_for_bin, # result = func_for_bin()
}.get(option)()
Example 4 (only values):
option = number['type']
result = {
'number': lambda: 10, # result = 10
'text': lambda: 'ten', # result = 'ten'
'binary': lambda: 0b101111, # result = 47
}.get(option)()
If you have a complicated case block you can consider using a function dictionary lookup table...
If you haven't done this before it's a good idea to step into your debugger and view exactly how the dictionary looks up each function.
NOTE: Do not use "()" inside the case/dictionary lookup or it will call each of your functions as the dictionary / case block is created. Remember this because you only want to call each function once using a hash style lookup.
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()
If you're searching extra-statement, as "switch", I built a Python module that extends Python. It's called ESPY as "Enhanced Structure for Python" and it's available for both Python 2.x and Python 3.x.
For example, in this case, a switch statement could be performed by the following code:
macro switch(arg1):
while True:
cont=False
val=%arg1%
socket case(arg2):
if val==%arg2% or cont:
cont=True
socket
socket else:
socket
break
That can be used like this:
a=3
switch(a):
case(0):
print("Zero")
case(1):
print("Smaller than 2"):
break
else:
print ("greater than 1")
So espy translate it in Python as:
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
Most of the answers here are pretty old, and especially the accepted ones, so it seems worth updating.
First, the official Python FAQ covers this, and recommends the elif chain for simple cases and the dict for larger or more complex cases. It also suggests a set of visit_ methods (a style used by many server frameworks) for some cases:
def dispatch(self, value):
method_name = 'visit_' + str(value)
method = getattr(self, method_name)
method()
The FAQ also mentions PEP 275, which was written to get an official once-and-for-all decision on adding C-style switch statements. But that PEP was actually deferred to Python 3, and it was only officially rejected as a separate proposal, PEP 3103. The answer was, of course, no—but the two PEPs have links to additional information if you're interested in the reasons or the history.
One thing that came up multiple times (and can be seen in PEP 275, even though it was cut out as an actual recommendation) is that if you're really bothered by having 8 lines of code to handle 4 cases, vs. the 6 lines you'd have in C or Bash, you can always write this:
if x == 1: print('first')
elif x == 2: print('second')
elif x == 3: print('third')
else: print('did not place')
This isn't exactly encouraged by PEP 8, but it's readable and not too unidiomatic.
Over the more than a decade since PEP 3103 was rejected, the issue of C-style case statements, or even the slightly more powerful version in Go, has been considered dead; whenever anyone brings it up on python-ideas or -dev, they're referred to the old decision.
However, the idea of full ML-style pattern matching arises every few years, especially since languages like Swift and Rust have adopted it. The problem is that it's hard to get much use out of pattern matching without algebraic data types. While Guido has been sympathetic to the idea, nobody's come up with a proposal that fits into Python very well. (You can read my 2014 strawman for an example.) This could change with dataclass in 3.7 and some sporadic proposals for a more powerful enum to handle sum types, or with various proposals for different kinds of statement-local bindings (like PEP 3150, or the set of proposals currently being discussed on -ideas). But so far, it hasn't.
There are also occasionally proposals for Perl 6-style matching, which is basically a mishmash of everything from elif to regex to single-dispatch type-switching.
Expanding on the "dict as switch" idea. If you want to use a default value for your switch:
def f(x):
try:
return {
'a': 1,
'b': 2,
}[x]
except KeyError:
return 'default'
I found that a common switch structure:
switch ...parameter...
case p1: v1; break;
case p2: v2; break;
default: v3;
can be expressed in Python as follows:
(lambda x: v1 if p1(x) else v2 if p2(x) else v3)
or formatted in a clearer way:
(lambda x:
v1 if p1(x) else
v2 if p2(x) else
v3)
Instead of being a statement, the Python version is an expression, which evaluates to a value.
The solutions I use:
A combination of 2 of the solutions posted here, which is relatively easy to read and supports defaults.
result = {
'a': lambda x: x * 5,
'b': lambda x: x + 7,
'c': lambda x: x - 2
}.get(whatToUse, lambda x: x - 22)(value)
where
.get('c', lambda x: x - 22)(23)
looks up "lambda x: x - 2" in the dict and uses it with x=23
.get('xxx', lambda x: x - 22)(44)
doesn't find it in the dict and uses the default "lambda x: x - 22" with x=44.
You can use a dispatched dict:
#!/usr/bin/env python
def case1():
print("This is case 1")
def case2():
print("This is case 2")
def case3():
print("This is case 3")
token_dict = {
"case1" : case1,
"case2" : case2,
"case3" : case3,
}
def main():
cases = ("case1", "case3", "case2", "case1")
for case in cases:
token_dict[case]()
if __name__ == '__main__':
main()
Output:
This is case 1
This is case 3
This is case 2
This is case 1
I didn't find the simple answer I was looking for anywhere on Google search. But I figured it out anyway. It's really quite simple. Decided to post it, and maybe prevent a few less scratches on someone else's head. The key is simply "in" and tuples. Here is the switch statement behavior with fall-through, including RANDOM fall-through.
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)
Provides:
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.
# 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
I was quite confused after reading the accepted answer, but this cleared it all up:
def numbers_to_strings(argument):
switcher = {
0: "zero",
1: "one",
2: "two",
}
return switcher.get(argument, "nothing")
This code is analogous to:
function(argument){
switch(argument) {
case 0:
return "zero";
case 1:
return "one";
case 2:
return "two";
default:
return "nothing";
}
}
Check the Source for more about dictionary mapping to functions.
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
I liked Mark Bies's answer
Since the x variable must used twice, I modified the lambda functions to parameterless.
I have to run with results[value](value)
In [2]: result = {
...: 'a': lambda x: 'A',
...: 'b': lambda x: 'B',
...: 'c': lambda x: 'C'
...: }
...: result['a']('a')
...:
Out[2]: 'A'
In [3]: result = {
...: 'a': lambda : 'A',
...: 'b': lambda : 'B',
...: 'c': lambda : 'C',
...: None: lambda : 'Nothing else matters'
...: }
...: result['a']()
...:
Out[3]: 'A'
Edit: I noticed that I can use None type with with dictionaries. So this would emulate switch ; case else
def f(x):
return 1 if x == 'a' else\
2 if x in 'bcd' else\
0 #default
Short and easy to read, has a default value and supports expressions in both conditions and return values.
However, it is less efficient than the solution with a dictionary. For example, Python has to scan through all the conditions before returning the default value.
Simple, not tested; each condition is evaluated independently: there is no fall-through, but all cases are evaluated (although the expression to switch on is only evaluated once), unless there is a break statement. For example,
for case in [expression]:
if case == 1:
print(end='Was 1. ')
if case == 2:
print(end='Was 2. ')
break
if case in (1, 2):
print(end='Was 1 or 2. ')
print(end='Was something. ')
prints Was 1. Was 1 or 2. Was something. (Dammit! Why can't I have trailing whitespace in inline code blocks?) if expression evaluates to 1, Was 2. if expression evaluates to 2, or Was something. if expression evaluates to something else.
There have been a lot of answers so far that have said, "we don't have a switch in Python, do it this way". However, I would like to point out that the switch statement itself is an easily-abused construct that can and should be avoided in most cases because they promote lazy programming. Case in point:
def ToUpper(lcChar):
if (lcChar == 'a' or lcChar == 'A'):
return 'A'
elif (lcChar == 'b' or lcChar == 'B'):
return 'B'
...
elif (lcChar == 'z' or lcChar == 'Z'):
return 'Z'
else:
return None # or something
Now, you could do this with a switch-statement (if Python offered one) but you'd be wasting your time because there are methods that do this just fine. Or maybe, you have something less obvious:
def ConvertToReason(code):
if (code == 200):
return 'Okay'
elif (code == 400):
return 'Bad Request'
elif (code == 404):
return 'Not Found'
else:
return None
However, this sort of operation can and should be handled with a dictionary because it will be faster, less complex, less prone to error and more compact.
And the vast majority of "use cases" for switch statements will fall into one of these two cases; there's just very little reason to use one if you've thought about your problem thoroughly.
So, rather than asking "how do I switch in Python?", perhaps we should ask, "why do I want to switch in Python?" because that's often the more interesting question and will often expose flaws in the design of whatever you're building.
Now, that isn't to say that switches should never be used either. State machines, lexers, parsers and automata all use them to some degree and, in general, when you start from a symmetrical input and go to an asymmetrical output they can be useful; you just need to make sure that you don't use the switch as a hammer because you see a bunch of nails in your code.
A solution I tend to use which also makes use of dictionaries is:
def decision_time( key, *args, **kwargs):
def action1()
"""This function is a closure - and has access to all the arguments"""
pass
def action2()
"""This function is a closure - and has access to all the arguments"""
pass
def action3()
"""This function is a closure - and has access to all the arguments"""
pass
return {1:action1, 2:action2, 3:action3}.get(key,default)()
This has the advantage that it doesn't try to evaluate the functions every time, and you just have to ensure that the outer function gets all the information that the inner functions need.
Defining:
def switch1(value, options):
if value in options:
options[value]()
allows you to use a fairly straightforward syntax, with the cases bundled into a map:
def sample1(x):
local = 'betty'
switch1(x, {
'a': lambda: print("hello"),
'b': lambda: (
print("goodbye," + local),
print("!")),
})
I kept trying to redefine switch in a way that would let me get rid of the "lambda:", but gave up. Tweaking the definition:
def switch(value, *maps):
options = {}
for m in maps:
options.update(m)
if value in options:
options[value]()
elif None in options:
options[None]()
Allowed me to map multiple cases to the same code, and to supply a default option:
def sample(x):
switch(x, {
_: lambda: print("other")
for _ in 'cdef'
}, {
'a': lambda: print("hello"),
'b': lambda: (
print("goodbye,"),
print("!")),
None: lambda: print("I dunno")
})
Each replicated case has to be in its own dictionary; switch() consolidates the dictionaries before looking up the value. It's still uglier than I'd like, but it has the basic efficiency of using a hashed lookup on the expression, rather than a loop through all the keys.
Expanding on Greg Hewgill's answer - We can encapsulate the dictionary-solution using a decorator:
def case(callable):
"""switch-case decorator"""
class case_class(object):
def __init__(self, *args, **kwargs):
self.args = args
self.kwargs = kwargs
def do_call(self):
return callable(*self.args, **self.kwargs)
return case_class
def switch(key, cases, default=None):
"""switch-statement"""
ret = None
try:
ret = case[key].do_call()
except KeyError:
if default:
ret = default.do_call()
finally:
return ret
This can then be used with the #case-decorator
#case
def case_1(arg1):
print 'case_1: ', arg1
#case
def case_2(arg1, arg2):
print 'case_2'
return arg1, arg2
#case
def default_case(arg1, arg2, arg3):
print 'default_case: ', arg1, arg2, arg3
ret = switch(somearg, {
1: case_1('somestring'),
2: case_2(13, 42)
}, default_case(123, 'astring', 3.14))
print ret
The good news are that this has already been done in NeoPySwitch-module. Simply install using pip:
pip install NeoPySwitch
Say I have a Python function that returns multiple values in a tuple:
def func():
return 1, 2
Is there a nice way to ignore one of the results rather than just assigning to a temporary variable? Say if I was only interested in the first value, is there a better way than this:
x, temp = func()
You can use x = func()[0] to return the first value, x = func()[1] to return the second, and so on.
If you want to get multiple values at a time, use something like x, y = func()[2:4].
One common convention is to use a "_" as a variable name for the elements of the tuple you wish to ignore. For instance:
def f():
return 1, 2, 3
_, _, x = f()
If you're using Python 3, you can you use the star before a variable (on the left side of an assignment) to have it be a list in unpacking.
# Example 1: a is 1 and b is [2, 3]
a, *b = [1, 2, 3]
# Example 2: a is 1, b is [2, 3], and c is 4
a, *b, c = [1, 2, 3, 4]
# Example 3: b is [1, 2] and c is 3
*b, c = [1, 2, 3]
# Example 4: a is 1 and b is []
a, *b = [1]
The common practice is to use the dummy variable _ (single underscore), as many have indicated here before.
However, to avoid collisions with other uses of that variable name (see this response) it might be a better practice to use __ (double underscore) instead as a throwaway variable, as pointed by ncoghlan. E.g.:
x, __ = func()
Remember, when you return more than one item, you're really returning a tuple. So you can do things like this:
def func():
return 1, 2
print func()[0] # prints 1
print func()[1] # prints 2
The best solution probably is to name things instead of returning meaningless tuples (unless there is some logic behind the order of the returned items). You can for example use a dictionary:
def func():
return {'lat': 1, 'lng': 2}
latitude = func()['lat']
You could even use namedtuple if you want to add extra information about what you are returning (it's not just a dictionary, it's a pair of coordinates):
from collections import namedtuple
Coordinates = namedtuple('Coordinates', ['lat', 'lng'])
def func():
return Coordinates(lat=1, lng=2)
latitude = func().lat
If the objects within your dictionary/tuple are strongly tied together then it may be a good idea to even define a class for it. That way you'll also be able to define more complex operations. A natural question that follows is: When should I be using classes in Python?
Most recent versions of python (≥ 3.7) have dataclasses which you can use to define classes with very few lines of code:
from dataclasses import dataclass
#dataclass
class Coordinates:
lat: float = 0
lng: float = 0
def func():
return Coordinates(lat=1, lng=2)
latitude = func().lat
The primary advantage of dataclasses over namedtuple is that its easier to extend, but there are other differences. Note that by default, dataclasses are mutable, but you can use #dataclass(frozen=True) instead of #dataclass to force them being immutable.
Here is a video that might help you pick the right data class for your use case.
Three simple choices.
Obvious
x, _ = func()
x, junk = func()
Hideous
x = func()[0]
And there are ways to do this with a decorator.
def val0( aFunc ):
def pick0( *args, **kw ):
return aFunc(*args,**kw)[0]
return pick0
func0= val0(func)
This seems like the best choice to me:
val1, val2, ignored1, ignored2 = some_function()
It's not cryptic or ugly (like the func()[index] method), and clearly states your purpose.
If this is a function that you use all the time but always discard the second argument, I would argue that it is less messy to create an alias for the function without the second return value using lambda.
def func():
return 1, 2
func_ = lambda: func()[0]
func_() # Prints 1
This is not a direct answer to the question. Rather it answers this question: "How do I choose a specific function output from many possible options?".
If you are able to write the function (ie, it is not in a library you cannot modify), then add an input argument that indicates what you want out of the function. Make it a named argument with a default value so in the "common case" you don't even have to specify it.
def fancy_function( arg1, arg2, return_type=1 ):
ret_val = None
if( 1 == return_type ):
ret_val = arg1 + arg2
elif( 2 == return_type ):
ret_val = [ arg1, arg2, arg1 * arg2 ]
else:
ret_val = ( arg1, arg2, arg1 + arg2, arg1 * arg2 )
return( ret_val )
This method gives the function "advanced warning" regarding the desired output. Consequently it can skip unneeded processing and only do the work necessary to get your desired output. Also because Python does dynamic typing, the return type can change. Notice how the example returns a scalar, a list or a tuple... whatever you like!
When you have many output from a function and you don't want to call it multiple times, I think the clearest way for selecting the results would be :
results = fct()
a,b = [results[i] for i in list_of_index]
As a minimum working example, also demonstrating that the function is called only once :
def fct(a):
b=a*2
c=a+2
d=a+b
e=b*2
f=a*a
print("fct called")
return[a,b,c,d,e,f]
results=fct(3)
> fct called
x,y = [results[i] for i in [1,4]]
And the values are as expected :
results
> [3,6,5,9,12,9]
x
> 6
y
> 12
For convenience, Python list indexes can also be used :
x,y = [results[i] for i in [0,-2]]
Returns : a = 3 and b = 12
It is possible to ignore every variable except the first with less syntax if you like. If we take your example,
# The function you are calling.
def func():
return 1, 2
# You seem to only be interested in the first output.
x, temp = func()
I have found the following to works,
x, *_ = func()
This approach "unpacks" with * all other variables into a "throwaway" variable _. This has the benefit of assigning the one variable you want and ignoring all variables behind it.
However, in many cases you may want an output that is not the first output of the function. In these cases, it is probably best to indicate this by using the func()[i] where i is the index location of the output you desire. In your case,
# i == 0 because of zero-index.
x = func()[0]
As a side note, if you want to get fancy in Python 3, you could do something like this,
# This works the other way around.
*_, y = func()
Your function only outputs two potential variables, so this does not look too powerful until you have a case like this,
def func():
return 1, 2, 3, 4
# I only want the first and last.
x, *_, d = func()
This question's answers are a community effort. Edit existing answers to improve this post. It is not currently accepting new answers or interactions.
I want to write a function in Python that returns different fixed values based on the value of an input index.
In other languages I would use a switch or case statement, but Python does not appear to have a switch statement. What are the recommended Python solutions in this scenario?
Python 3.10 (2021) introduced the match-case statement which provides a first-class implementation of a "switch" for Python. For example:
def f(x):
match x:
case 'a':
return 1
case 'b':
return 2
case _:
return 0 # 0 is the default case if x is not found
The match-case statement is considerably more powerful than this simple example.
The original answer below was written in 2008, before match-case was available:
You could use a dictionary:
def f(x):
return {
'a': 1,
'b': 2,
}[x]
If you'd like defaults, you could use the dictionary get(key[, default]) function:
def f(x):
return {
'a': 1,
'b': 2
}.get(x, 9) # 9 will be returned default if x is not found
I've always liked doing it this way
result = {
'a': lambda x: x * 5,
'b': lambda x: x + 7,
'c': lambda x: x - 2
}[value](x)
From here
In addition to the dictionary methods (which I really like, BTW), you can also use if-elif-else to obtain the switch/case/default functionality:
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
This of course is not identical to switch/case - you cannot have fall-through as easily as leaving off the break statement, but you can have a more complicated test. Its formatting is nicer than a series of nested ifs, even though functionally that's what it is closer to.
Python >= 3.10
Wow, Python 3.10+ now has a match/case syntax which is like switch/case and more!
PEP 634 -- Structural Pattern Matching
Selected features of match/case
1 - Match values:
Matching values is similar to a simple switch/case in another language:
match something:
case 1 | 2 | 3:
# Match 1-3.
case _:
# Anything else.
#
# Match will throw an error if this is omitted
# and it doesn't match any of the other patterns.
2 - Match structural patterns:
match something:
case str() | bytes():
# Match a string like object.
case [str(), int()]:
# Match a `str` and an `int` sequence
# (`list` or a `tuple` but not a `set` or an iterator).
case [_, _]:
# Match a sequence of 2 variables.
# To prevent a common mistake, sequence patterns don’t match strings.
case {"bandwidth": 100, "latency": 300}:
# Match this dict. Extra keys are ignored.
3 - Capture variables
Parse an object; saving it as variables:
match something:
case [name, count]
# Match a sequence of any two objects and parse them into the two variables.
case [x, y, *rest]:
# Match a sequence of two or more objects,
# binding object #3 and on into the rest variable.
case bytes() | str() as text:
# Match any string like object and save it to the text variable.
Capture variables can be useful when parsing data (such as JSON or HTML) that may come in one of a number of different patterns.
Capture variables is a feature. But it also means that you need to use dotted constants (ex: COLOR.RED) only. Otherwise, the constant will be treated as a capture variable and overwritten.
More sample usage:
match something:
case 0 | 1 | 2:
# Matches 0, 1 or 2 (value).
print("Small number")
case [] | [_]:
# Matches an empty or single value sequence (structure).
# Matches lists and tuples but not sets.
print("A short sequence")
case str() | bytes():
# Something of `str` or `bytes` type (data type).
print("Something string-like")
case _:
# Anything not matched by the above.
print("Something else")
Python <= 3.9
My favorite Python recipe for switch/case was:
choices = {'a': 1, 'b': 2}
result = choices.get(key, 'default')
Short and simple for simple scenarios.
Compare to 11+ lines of C code:
// C Language version of a simple 'switch/case'.
switch( key )
{
case 'a' :
result = 1;
break;
case 'b' :
result = 2;
break;
default :
result = -1;
}
You can even assign multiple variables by using tuples:
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))
Usage:
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
Tests:
n = 2
#Result:
#n is an even number.
#n is a prime number.
n = 11
#Result:
#Only single-digit numbers are allowed.
My favorite one is a really nice recipe. It's the closest one I've seen to actual switch case statements, especially in features.
class switch(object):
def __init__(self, value):
self.value = value
self.fall = False
def __iter__(self):
"""Return the match method once, then stop"""
yield self.match
raise StopIteration
def match(self, *args):
"""Indicate whether or not to enter a case suite"""
if self.fall or not args:
return True
elif self.value in args: # changed for v1.5, see below
self.fall = True
return True
else:
return False
Here's an example:
# 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!"
Some of the comments indicated that a context manager solution using with foo as case rather than for case in foo might be cleaner, and for large switch statements the linear rather than quadratic behavior might be a nice touch. Part of the value in this answer with a for loop is the ability to have breaks and fallthrough, and if we're willing to play with our choice of keywords a little bit we can get that in a context manager too:
class Switch:
def __init__(self, value):
self.value = value
self._entered = False
self._broken = False
self._prev = None
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
return False # Allows a traceback to occur
def __call__(self, *values):
if self._broken:
return False
if not self._entered:
if values and self.value not in values:
return False
self._entered, self._prev = True, values
return True
if self._prev is None:
self._prev = values
return True
if self._prev != values:
self._broken = True
return False
if self._prev == values:
self._prev = None
return False
#property
def default(self):
return self()
Here's an example:
# Prints 'bar' then 'baz'.
with Switch(2) as case:
while case(0):
print('foo')
while case(1, 2, 3):
print('bar')
while case(4, 5):
print('baz')
break
while case.default:
print('default')
break
class Switch:
def __init__(self, value):
self.value = value
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
return False # Allows a traceback to occur
def __call__(self, *values):
return self.value in values
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
There's a pattern that I learned from Twisted Python code.
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'
You can use it any time you need to dispatch on a token and execute extended piece of code. In a state machine you would have state_ methods, and dispatch on self.state. This switch can be cleanly extended by inheriting from base class and defining your own do_ methods. Often times you won't even have do_ methods in the base class.
Edit: how exactly is that used
In case of SMTP you will receive HELO from the wire. The relevant code (from twisted/mail/smtp.py, modified for our case) looks like this
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
You'll receive ' HELO foo.bar.com ' (or you might get 'QUIT' or 'RCPT TO: foo'). This is tokenized into parts as ['HELO', 'foo.bar.com']. The actual method lookup name is taken from parts[0].
(The original method is also called state_COMMAND, because it uses the same pattern to implement a state machine, i.e. getattr(self, 'state_' + self.mode))
I'm just going to drop my two cents in here. The reason there isn't a case/switch statement in Python is because Python follows the principle of "there's only one right way to do something". So obviously you could come up with various ways of recreating switch/case functionality, but the Pythonic way of accomplishing this is the if/elif construct. I.e.,
if something:
return "first thing"
elif somethingelse:
return "second thing"
elif yetanotherthing:
return "third thing"
else:
return "default thing"
I just felt PEP 8 deserved a nod here. One of the beautiful things about Python is its simplicity and elegance. That is largely derived from principles laid out in PEP 8, including "There's only one right way to do something."
Let's say you don't want to just return a value, but want to use methods that change something on an object. Using the approach stated here would be:
result = {
'a': obj.increment(x),
'b': obj.decrement(x)
}.get(value, obj.default(x))
Here Python evaluates all methods in the dictionary.
So even if your value is 'a', the object will get incremented and decremented by x.
Solution:
func, args = {
'a' : (obj.increment, (x,)),
'b' : (obj.decrement, (x,)),
}.get(value, (obj.default, (x,)))
result = func(*args)
So you get a list containing a function and its arguments. This way, only the function pointer and the argument list get returned, not evaluated. 'result' then evaluates the returned function call.
Solution to run functions:
result = {
'case1': foo1,
'case2': foo2,
'case3': foo3,
}.get(option)(parameters_optional)
where foo1(), foo2() and foo3() are functions
Example 1 (with parameters):
option = number['type']
result = {
'number': value_of_int, # result = value_of_int(number['value'])
'text': value_of_text, # result = value_of_text(number['value'])
'binary': value_of_bin, # result = value_of_bin(number['value'])
}.get(option)(value['value'])
Example 2 (no parameters):
option = number['type']
result = {
'number': func_for_number, # result = func_for_number()
'text': func_for_text, # result = func_for_text()
'binary': func_for_bin, # result = func_for_bin()
}.get(option)()
Example 4 (only values):
option = number['type']
result = {
'number': lambda: 10, # result = 10
'text': lambda: 'ten', # result = 'ten'
'binary': lambda: 0b101111, # result = 47
}.get(option)()
If you have a complicated case block you can consider using a function dictionary lookup table...
If you haven't done this before it's a good idea to step into your debugger and view exactly how the dictionary looks up each function.
NOTE: Do not use "()" inside the case/dictionary lookup or it will call each of your functions as the dictionary / case block is created. Remember this because you only want to call each function once using a hash style lookup.
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()
If you're searching extra-statement, as "switch", I built a Python module that extends Python. It's called ESPY as "Enhanced Structure for Python" and it's available for both Python 2.x and Python 3.x.
For example, in this case, a switch statement could be performed by the following code:
macro switch(arg1):
while True:
cont=False
val=%arg1%
socket case(arg2):
if val==%arg2% or cont:
cont=True
socket
socket else:
socket
break
That can be used like this:
a=3
switch(a):
case(0):
print("Zero")
case(1):
print("Smaller than 2"):
break
else:
print ("greater than 1")
So espy translate it in Python as:
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
Most of the answers here are pretty old, and especially the accepted ones, so it seems worth updating.
First, the official Python FAQ covers this, and recommends the elif chain for simple cases and the dict for larger or more complex cases. It also suggests a set of visit_ methods (a style used by many server frameworks) for some cases:
def dispatch(self, value):
method_name = 'visit_' + str(value)
method = getattr(self, method_name)
method()
The FAQ also mentions PEP 275, which was written to get an official once-and-for-all decision on adding C-style switch statements. But that PEP was actually deferred to Python 3, and it was only officially rejected as a separate proposal, PEP 3103. The answer was, of course, no—but the two PEPs have links to additional information if you're interested in the reasons or the history.
One thing that came up multiple times (and can be seen in PEP 275, even though it was cut out as an actual recommendation) is that if you're really bothered by having 8 lines of code to handle 4 cases, vs. the 6 lines you'd have in C or Bash, you can always write this:
if x == 1: print('first')
elif x == 2: print('second')
elif x == 3: print('third')
else: print('did not place')
This isn't exactly encouraged by PEP 8, but it's readable and not too unidiomatic.
Over the more than a decade since PEP 3103 was rejected, the issue of C-style case statements, or even the slightly more powerful version in Go, has been considered dead; whenever anyone brings it up on python-ideas or -dev, they're referred to the old decision.
However, the idea of full ML-style pattern matching arises every few years, especially since languages like Swift and Rust have adopted it. The problem is that it's hard to get much use out of pattern matching without algebraic data types. While Guido has been sympathetic to the idea, nobody's come up with a proposal that fits into Python very well. (You can read my 2014 strawman for an example.) This could change with dataclass in 3.7 and some sporadic proposals for a more powerful enum to handle sum types, or with various proposals for different kinds of statement-local bindings (like PEP 3150, or the set of proposals currently being discussed on -ideas). But so far, it hasn't.
There are also occasionally proposals for Perl 6-style matching, which is basically a mishmash of everything from elif to regex to single-dispatch type-switching.
Expanding on the "dict as switch" idea. If you want to use a default value for your switch:
def f(x):
try:
return {
'a': 1,
'b': 2,
}[x]
except KeyError:
return 'default'
I found that a common switch structure:
switch ...parameter...
case p1: v1; break;
case p2: v2; break;
default: v3;
can be expressed in Python as follows:
(lambda x: v1 if p1(x) else v2 if p2(x) else v3)
or formatted in a clearer way:
(lambda x:
v1 if p1(x) else
v2 if p2(x) else
v3)
Instead of being a statement, the Python version is an expression, which evaluates to a value.
The solutions I use:
A combination of 2 of the solutions posted here, which is relatively easy to read and supports defaults.
result = {
'a': lambda x: x * 5,
'b': lambda x: x + 7,
'c': lambda x: x - 2
}.get(whatToUse, lambda x: x - 22)(value)
where
.get('c', lambda x: x - 22)(23)
looks up "lambda x: x - 2" in the dict and uses it with x=23
.get('xxx', lambda x: x - 22)(44)
doesn't find it in the dict and uses the default "lambda x: x - 22" with x=44.
You can use a dispatched dict:
#!/usr/bin/env python
def case1():
print("This is case 1")
def case2():
print("This is case 2")
def case3():
print("This is case 3")
token_dict = {
"case1" : case1,
"case2" : case2,
"case3" : case3,
}
def main():
cases = ("case1", "case3", "case2", "case1")
for case in cases:
token_dict[case]()
if __name__ == '__main__':
main()
Output:
This is case 1
This is case 3
This is case 2
This is case 1
I didn't find the simple answer I was looking for anywhere on Google search. But I figured it out anyway. It's really quite simple. Decided to post it, and maybe prevent a few less scratches on someone else's head. The key is simply "in" and tuples. Here is the switch statement behavior with fall-through, including RANDOM fall-through.
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)
Provides:
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.
# 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
I was quite confused after reading the accepted answer, but this cleared it all up:
def numbers_to_strings(argument):
switcher = {
0: "zero",
1: "one",
2: "two",
}
return switcher.get(argument, "nothing")
This code is analogous to:
function(argument){
switch(argument) {
case 0:
return "zero";
case 1:
return "one";
case 2:
return "two";
default:
return "nothing";
}
}
Check the Source for more about dictionary mapping to functions.
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
I liked Mark Bies's answer
Since the x variable must used twice, I modified the lambda functions to parameterless.
I have to run with results[value](value)
In [2]: result = {
...: 'a': lambda x: 'A',
...: 'b': lambda x: 'B',
...: 'c': lambda x: 'C'
...: }
...: result['a']('a')
...:
Out[2]: 'A'
In [3]: result = {
...: 'a': lambda : 'A',
...: 'b': lambda : 'B',
...: 'c': lambda : 'C',
...: None: lambda : 'Nothing else matters'
...: }
...: result['a']()
...:
Out[3]: 'A'
Edit: I noticed that I can use None type with with dictionaries. So this would emulate switch ; case else
def f(x):
return 1 if x == 'a' else\
2 if x in 'bcd' else\
0 #default
Short and easy to read, has a default value and supports expressions in both conditions and return values.
However, it is less efficient than the solution with a dictionary. For example, Python has to scan through all the conditions before returning the default value.
Simple, not tested; each condition is evaluated independently: there is no fall-through, but all cases are evaluated (although the expression to switch on is only evaluated once), unless there is a break statement. For example,
for case in [expression]:
if case == 1:
print(end='Was 1. ')
if case == 2:
print(end='Was 2. ')
break
if case in (1, 2):
print(end='Was 1 or 2. ')
print(end='Was something. ')
prints Was 1. Was 1 or 2. Was something. (Dammit! Why can't I have trailing whitespace in inline code blocks?) if expression evaluates to 1, Was 2. if expression evaluates to 2, or Was something. if expression evaluates to something else.
There have been a lot of answers so far that have said, "we don't have a switch in Python, do it this way". However, I would like to point out that the switch statement itself is an easily-abused construct that can and should be avoided in most cases because they promote lazy programming. Case in point:
def ToUpper(lcChar):
if (lcChar == 'a' or lcChar == 'A'):
return 'A'
elif (lcChar == 'b' or lcChar == 'B'):
return 'B'
...
elif (lcChar == 'z' or lcChar == 'Z'):
return 'Z'
else:
return None # or something
Now, you could do this with a switch-statement (if Python offered one) but you'd be wasting your time because there are methods that do this just fine. Or maybe, you have something less obvious:
def ConvertToReason(code):
if (code == 200):
return 'Okay'
elif (code == 400):
return 'Bad Request'
elif (code == 404):
return 'Not Found'
else:
return None
However, this sort of operation can and should be handled with a dictionary because it will be faster, less complex, less prone to error and more compact.
And the vast majority of "use cases" for switch statements will fall into one of these two cases; there's just very little reason to use one if you've thought about your problem thoroughly.
So, rather than asking "how do I switch in Python?", perhaps we should ask, "why do I want to switch in Python?" because that's often the more interesting question and will often expose flaws in the design of whatever you're building.
Now, that isn't to say that switches should never be used either. State machines, lexers, parsers and automata all use them to some degree and, in general, when you start from a symmetrical input and go to an asymmetrical output they can be useful; you just need to make sure that you don't use the switch as a hammer because you see a bunch of nails in your code.
A solution I tend to use which also makes use of dictionaries is:
def decision_time( key, *args, **kwargs):
def action1()
"""This function is a closure - and has access to all the arguments"""
pass
def action2()
"""This function is a closure - and has access to all the arguments"""
pass
def action3()
"""This function is a closure - and has access to all the arguments"""
pass
return {1:action1, 2:action2, 3:action3}.get(key,default)()
This has the advantage that it doesn't try to evaluate the functions every time, and you just have to ensure that the outer function gets all the information that the inner functions need.
Defining:
def switch1(value, options):
if value in options:
options[value]()
allows you to use a fairly straightforward syntax, with the cases bundled into a map:
def sample1(x):
local = 'betty'
switch1(x, {
'a': lambda: print("hello"),
'b': lambda: (
print("goodbye," + local),
print("!")),
})
I kept trying to redefine switch in a way that would let me get rid of the "lambda:", but gave up. Tweaking the definition:
def switch(value, *maps):
options = {}
for m in maps:
options.update(m)
if value in options:
options[value]()
elif None in options:
options[None]()
Allowed me to map multiple cases to the same code, and to supply a default option:
def sample(x):
switch(x, {
_: lambda: print("other")
for _ in 'cdef'
}, {
'a': lambda: print("hello"),
'b': lambda: (
print("goodbye,"),
print("!")),
None: lambda: print("I dunno")
})
Each replicated case has to be in its own dictionary; switch() consolidates the dictionaries before looking up the value. It's still uglier than I'd like, but it has the basic efficiency of using a hashed lookup on the expression, rather than a loop through all the keys.
Expanding on Greg Hewgill's answer - We can encapsulate the dictionary-solution using a decorator:
def case(callable):
"""switch-case decorator"""
class case_class(object):
def __init__(self, *args, **kwargs):
self.args = args
self.kwargs = kwargs
def do_call(self):
return callable(*self.args, **self.kwargs)
return case_class
def switch(key, cases, default=None):
"""switch-statement"""
ret = None
try:
ret = case[key].do_call()
except KeyError:
if default:
ret = default.do_call()
finally:
return ret
This can then be used with the #case-decorator
#case
def case_1(arg1):
print 'case_1: ', arg1
#case
def case_2(arg1, arg2):
print 'case_2'
return arg1, arg2
#case
def default_case(arg1, arg2, arg3):
print 'default_case: ', arg1, arg2, arg3
ret = switch(somearg, {
1: case_1('somestring'),
2: case_2(13, 42)
}, default_case(123, 'astring', 3.14))
print ret
The good news are that this has already been done in NeoPySwitch-module. Simply install using pip:
pip install NeoPySwitch