patternpythonMinor
Switch function in Python
Viewed 0 times
switchfunctionpython
Problem
I wrote this
I use
Can this be optimized/made more pythonic?
switch function for Python, as there isn't a built-in one and most of the Googlable ones doesn't execute code, but only return something (I admit I haven't looked much further than a single Stack Oveflow page to see what people use, but a lot of the solutions are unnecessarily complex):def switch(variable, **cases):
for case in cases.keys():
if variable is case:
exec(cases[case])I use
**cases, due to this syntax:def switch(variable, **cases):
for case in cases.keys():
if variable is case:
exec(cases[case])
some_string = "a"
switch(some_string,
b="print('It is b!')",
a="print('It is a!')")
some_string = "b"
switch(some_string,
b="print('It is b!')",
a="print('It is a!')")
some_string = "c"
switch(some_string,
b="print('It is b!')",
a="print('It is a!')")Can this be optimized/made more pythonic?
Solution
The most Pythonic way to do is to define a (reusable) dictionary. Most often this dictionary contains callables, but not necessarily.
The least efficient way to do it, though, is to loop over each possibility as you do. It computes in \$O(n)\$ rather than \$O(1)\$ as a dictionnary can offer. And avoid the capability of short-circuit a succession of
So, at the very least, use something like
However, I find that defining the various statements at each call is innefficient. As I said, it's better to be able to define a reusable dictionary. I would also advise against the use of
Usage being:
But way... This
Or, if you trully insist on using strings rather than real callable objects:
The least efficient way to do it, though, is to loop over each possibility as you do. It computes in \$O(n)\$ rather than \$O(1)\$ as a dictionnary can offer. And avoid the capability of short-circuit a succession of
if...elif...elif...else can offer.So, at the very least, use something like
def switch(value, **cases):
try:
statement = cases[value]
except KeyError:
pass
else:
exec(statement)However, I find that defining the various statements at each call is innefficient. As I said, it's better to be able to define a reusable dictionary. I would also advise against the use of
exec and make the function more generic; letting the user decide what to do with the retrived value:def switch(value, cases, default=None):
try:
return cases[value]
except KeyError:
return defaultUsage being:
PRINT_STUFF = {
'a': lambda: print("It's a!"),
'b': lambda: print("It's b!"),
}
switch('a', PRINT_STUFF, lambda: None)()
switch('b', PRINT_STUFF, lambda: None)()
switch('c', PRINT_STUFF, lambda: None)()But way... This
try..except reminds me of something... Oh the dict.get method. So there is really no need for switch:PRINT_STUFF.get('a', lambda: None)()
PRINT_STUFF.get('b', lambda: None)()
PRINT_STUFF.get('c', lambda: None)()Or, if you trully insist on using strings rather than real callable objects:
PRINT_STUFF = {
'a': 'print("It\'s a!")',
'b': 'print("It\'s b!")',
}
exec(PRINT_STUFF.get('a', 'pass'))
exec(PRINT_STUFF.get('b', 'pass'))
exec(PRINT_STUFF.get('c', 'pass'))Code Snippets
def switch(value, **cases):
try:
statement = cases[value]
except KeyError:
pass
else:
exec(statement)def switch(value, cases, default=None):
try:
return cases[value]
except KeyError:
return defaultPRINT_STUFF = {
'a': lambda: print("It's a!"),
'b': lambda: print("It's b!"),
}
switch('a', PRINT_STUFF, lambda: None)()
switch('b', PRINT_STUFF, lambda: None)()
switch('c', PRINT_STUFF, lambda: None)()PRINT_STUFF.get('a', lambda: None)()
PRINT_STUFF.get('b', lambda: None)()
PRINT_STUFF.get('c', lambda: None)()PRINT_STUFF = {
'a': 'print("It\'s a!")',
'b': 'print("It\'s b!")',
}
exec(PRINT_STUFF.get('a', 'pass'))
exec(PRINT_STUFF.get('b', 'pass'))
exec(PRINT_STUFF.get('c', 'pass'))Context
StackExchange Code Review Q#149922, answer score: 6
Revisions (0)
No revisions yet.