调度请求时,if-elif-elif-elif的Python最佳实践

时间:2013-01-10 17:12:19

标签: python if-statement switch-statement dispatch

我有5组请求的类别定义为python dicts,例如:

category1 = {'type1', 'type2', 'type3'}
category2 = {'type4', 'type5'}
category3 = {'type6', 'type7', 'type8', 'type9'}
category4 = {'type10', 'type11'}
category5 = {'type12', 'type13', 'type14'}

我需要使用他们的类别来处理请求,例如:

if request_type in category1:
    # process category1 request
    process_category1_request(...)
elif request_type in category2:
    # process category2 request
    process_category2_request(...)
elif...

我需要使用请求类型将请求分派给不同的函数来处理它。

我已经知道有些方法可以在Python中调度这些请求而无需使用if-elif,但我的问题是:在保持代码干净简单的同时,最好的方法是什么?

5 个答案:

答案 0 :(得分:15)

如果request_type可以出现在多个类别中,您可以使用元组按优先级顺序循环显示它们:

categories = (
    (category1, dispatch1method), 
    (category2, dispatch2method),
    (category3, dispatch3method),
    (category4, dispatch4method),
    (category5, dispatch5method),
)

next(method for cat, method in categories if request_type in cat)(arguments)

否则使用dict()将类别类型映射到调度方法;重用上面相同的元组映射来构建调度:

category_dispatch = {}
for cat, dispatch in categories:
    category_dispatch.update(dict.fromkeys(cat.keys(), dispatch))

然后只需在其上查找请求类型:

category_dispatch[request_type](arguments)

这样的映射查找比通过元组的扫描更快,我们必须依次测试每个类别,直到找到匹配为止。

事实上,可以通过颠倒相同的元组结构来维持优先级排序:

category_dispatch = {}
for cat, dispatch in reversed(categories):
    category_dispatch.update(dict.fromkeys(cat.keys(), dispatch))

因为现在给定request_type密钥的最高优先级映射将最后输入category_dispatch结构。即使请求类型存在于多个类别中,这也将为您提供最快的发送。

缺点是,如果您的category*映射是动态的(随着时间的推移,请求类型会被添加到不同类别或从中删除),您需要维护category_dispatch dict以反映这些更改。< / p>

答案 1 :(得分:4)

我认为最干净的可能是两张地图,以使代码最具可读性。

type_category_map = {"type1" : "category1", 
"type2" : "category1", , 
"type3" : "category1",
"type4" : "category2",
....
"type14" : "category5"}

category_function_map = {"category1" : "handler1_function",
"category2" : "handler2_function,
....
}

然后python就是这样:

category = type_category_map[request_type]
handler_function = category_function_map[category]
handler_function(request)

我认为,有一种方法可以用单一数据结构来实现,但没有一种方法可以像我这样清楚易懂。

答案 2 :(得分:3)

将您的类别映射到处理程序。与您将拥有的地图大小无关 O(1)访问时间。

MAP = {
  'cat1': handler1,
  'cat2': handler2,
   ....
}

MAP[request_type](...)

答案 3 :(得分:3)

您不能指定像

这样的字典
  

category1 = {'type1','type2','type3'}

你这里没有键值。

关于你的问题,这是一个对你有利的简单解决方案吗?

dispatchers = {}

def register_dispatches(types, dispatcher):
    dispatchers.update(dict.fromkeys(types, dispatcher))

def process(request_type, *args, **kwargs):
    dispatchers[request_type](*args, **kwargs)


register_dispatches(['type1', 'type2', 'type3'], process_category1_request)
register_dispatches(['type4', 'type5'], process_category2_request)
...
process(request_type, ...)

答案 4 :(得分:2)

categories = {request1 : dispatch1, request2 : dispatch2, request3 : dispatch3}
for category, dispatch in categories.iteritems():
    if something in category:
        dispatch(something)

这个怎么样?