可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I know you can use a dictionary as an alternative to a switch statement such as the following:
def printMessage(mystring):
# Switch statement without a dictionary
if mystring == "helloworld":
print "say hello"
elif mystring == "byeworld":
print "say bye"
elif mystring == "goodafternoonworld":
print "good afternoon"
def printMessage(mystring):
# Dictionary equivalent of a switch statement
myDictionary = {"helloworld": "say hello",
"byeworld": "say bye",
"goodafternoonworld": "good afternoon"}
print myDictionary[mystring]
However if conditions are used, other than equality (==) which return true of false these cant be mapped as easily i.e.:
if i > 0.5:
print "greater than 0.5"
elif i == 5:
print "it is equal to 5"
elif i > 5 and i < 6:
print "somewhere between 5 and 6"
The above cannot be directly converted to a dictionary key-value pair as is:
# this does not work
mydictionary = { i > 0.5: "greater than 0.5" }
A lambda can be used since it is hash-able but the only way to get the resulting string out of the map is by passing the same lambda object into the dictionary and not when the evaluation of the lambda is true:
x = lambda i: i > 0.5
mydictionary[x] = "greater than 0.5"
# you can get the string by doing this:
mydictionary[x]
# which doesnt result in the evaluation of x
# however a lambda is a hashable item in a dictionary
mydictionary = {lambda i: i > 0.5: "greater than 0.5"}
Does anyone know of a technique or method to create a mapping between a lambda evaluation and a return value?
(this maybe similar to pattern matching in functional language)
回答1:
Your conditions are sequential in nature; you want to test one after the other, not map a small number of keys to a value here. Changing the order of the conditions could alter the outcome; a value of 5
results in "greater than 0.5"
in your sample, not "it is equal to 5"
.
Use a list of tuples:
myconditions = [
(lambda i: i > 0.5, "greater than 0.5"),
(lambda i: i == 5, "it is equal to 5"),
(lambda i: i > 5 and i < 6, "somewhere between 5 and 6"),
]
after which you can access each one in turn until one matches:
for test, message in myconditions:
if test(i):
return message
Re-ordering the tests will change the outcome.
A dictionary works for your first example because there is a simple equality test against multiple static values that is optimised by a dictionary, but there are no such simple equalities available here.
回答2:
You can't use a dictionary to map arbitrary conditionals since more than one of them could be true at the same time. Instead you need to evaluate each one sequentially and execute the associated code the first time a true one is encountered. Here's an outline of one way to formally implement something like that which even allows the equivalent of a default:
case.
from collections import namedtuple
Case = namedtuple('Case', ['condition', 'code'])
cases = (Case('i > 0.5',
"""print 'greater than 0.5'"""),
Case('i == 5',
"""print 'it is equal to 5'"""),
Case('i > 5 and i < 6',
"""print 'somewhere between 5 and 6'"""))
def switch(cases, **namespace):
for case in cases:
if eval(case.condition, namespace):
exec(case.code, namespace)
break
else:
print 'default case'
switch(cases, i=5)
Output:
greater than 0.5
回答3:
Not directly related, but I often use a paradigm similar to the example below for replacing cascading ifs with a dictionaruy lookup.
def multipleifs(a=None,b=None,c=None,d=None,e=None):
""" Func1 with cascaded if
>>> multipleifs(10,20,30,40,50)
160
"""
x=10
if a:
x += 10
if b:
x += 20
if c:
x += 30
if d:
x += 40
if e:
x += 50
return x
def dictif(a=None,b=None,c=None,d=None,e=None):
""" Func2 with dictionary replacing multiple ifs
>>> dictif(10,20,30,40,50)
160
"""
x, mydict = 10, dict(enumerate([10,20,30,40,50]))
for count, item in enumerate([a,b,c,d,e]):
if item: x += mydict.get(count,0)
return x