7

我有 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...

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

我已经知道有一些方法可以在不需要使用 if-elif 的情况下在 Python 中分派这些请求,但我的问题是:在保持代码简洁明了的同时,最好的方法是什么?

4

5 回答 5

16

如果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)

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

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_dispatchdict 以反映这些更改。

于 2013-01-10T17:15:39.557 回答
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)

有办法用单一的数据结构来做到这一点,但我认为没有一种方法能像这样清晰易懂。

于 2013-01-10T17:32:43.867 回答
3

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

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

MAP[request_type](...)
于 2013-01-10T17:15:46.753 回答
3

你不能指定一个像

类别1 = {'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, ...)
于 2013-01-10T17:21:15.760 回答
2
categories = {request1 : dispatch1, request2 : dispatch2, request3 : dispatch3}
for category, dispatch in categories.iteritems():
    if something in category:
        dispatch(something)

这个怎么样?

于 2013-01-10T17:15:35.780 回答