这是执行函数的“Pythonic”方式吗?适用于元组值的Python switch语句?
我遇到了一种情况,有六种可能的情况可以对应四个不同的结果。我在想,是否可以用字典来代替冗长的if/else语句,这样就像在C#或PHP中使用“switch”语句一样,这样写会不会更符合Python的风格。
我的“switch”语句依赖于两个值,我用这两个值来构建一个元组,然后用这个元组作为字典的键,字典就充当我的“switch”。我会从另外两个函数(数据库调用)中获取元组的值,这就是我有one()和zero()这两个示例函数的原因。
这是我在Python交互式环境中玩的时候想到的代码模式:
def one():
#Simulated database value
return 1
def zero():
return 0
def run():
#Shows the correct function ran
print "RUN"
return 1
def walk():
print "WALK"
return 1
def main():
switch_dictionary = {}
#These are the values that I will want to use to decide
#which functions to use
switch_dictionary[(0,0)] = run
switch_dictionary[(1,1)] = walk
#These are the tuples that I will build from the database
zero_tuple = (zero(), zero())
one_tuple = (one(), one())
#These actually run the functions. In practice I will simply
#have the one tuple which is dependent on the database information
#to run the function that I defined before
switch_dictionary[zero_tuple]()
switch_dictionary[one_tuple]()
我还没有写出实际的代码,不然我会把它贴在这里,因为我想知道这种方法是否被认为是Python的最佳实践。我还是大学里的Python学习者,如果这种方法是个坏习惯,我希望在进入真实世界之前就改掉它。
注意,执行上面的代码结果是预期的,简单地输出“RUN”和“WALK”。
编辑
对于感兴趣的朋友们,这是相关代码的最终版本。它被用于一个Google App Engine的应用程序。你会发现这段代码比我之前的粗略示例整洁得多。它的效果比我之前复杂的if/else结构要好得多。
def GetAssignedAgent(self):
tPaypal = PaypalOrder() #Parent class for this function
tAgents = []
Switch = {}
#These are the different methods for the actions to take
Switch[(0,0)] = tPaypal.AssignNoAgent
Switch[(0,1)] = tPaypal.UseBackupAgents
Switch[(0,2)] = tPaypal.UseBackupAgents
Switch[(1,0)] = tPaypal.UseFullAgents
Switch[(1,1)] = tPaypal.UseFullAndBackupAgents
Switch[(1,2)] = tPaypal.UseFullAndBackupAgents
Switch[(2,0)] = tPaypal.UseFullAgents
Switch[(2,1)] = tPaypal.UseFullAgents
Switch[(2,2)] = tPaypal.UseFullAgents
#I'm only interested in the number up to 2, which is why
#I can consider the Switch dictionary to be all options available.
#The "state" is the current status of the customer agent system
tCurrentState = (tPaypal.GetNumberofAvailableAgents(),
tPaypal.GetNumberofBackupAgents())
tAgents = Switch[tCurrentState]()
2 个回答
在Python编程中,根据字典或序列查找来调用函数是一种比较常见的做法。
考虑到你使用索引来查找,使用列表的列表也是可以的:
switch_list = [[run, None], [None, walk]]
...
switch_list[zero_tuple]()
最符合Python风格的做法是既能清晰明了,又能满足其他操作需求。在你的例子中,查找的元组似乎没有什么特别的含义,这样就让操作的意图变得模糊了,像是用了一些神秘的常量。要确保你的业务逻辑在调用机制中不会被忽视。使用有意义的名称来命名这些常量会更有帮助。
考虑使用这个表达方式:
>>> def run():
... print 'run'
...
>>> def walk():
... print 'walk'
...
>>> def talk():
... print 'talk'
>>> switch={'run':run,'walk':walk,'talk':talk}
>>> switch['run']()
run
我觉得这个比你现在的写法更容易读懂。
编辑
这个写法也可以:
>>> switch={0:run,1:walk}
>>> switch[0]()
run
>>> switch[max(0,1)]()
walk
你甚至可以把这个表达方式用在 switch / default
这样的结构里:
>>> default_value=1
>>> try:
... switch[49]()
... except KeyError:
... switch[default_value]()
或者(虽然不太容易读,但更简洁):
>>> switch[switch.get(49,default_value)]()
walk
编辑 2
同样的表达方式,扩展到你的评论里:
>>> def get_t1():
... return 0
...
>>> def get_t2():
... return 1
...
>>> switch={(get_t1(),get_t2()):run}
>>> switch
{(0, 1): <function run at 0x100492d70>}
可读性很重要。