2013-03-15 2 views
0

Я составляю обработчик для обработки различных типов данных. Вот мое текущее решение:Как эффективно инкапсулировать обработчики в Python?

def get_handler_by_type(type): 
    def handler_for_type_A: 
     ... 
     #code for processing data type A 

    def handler_for_type_B: 
     ... 
     #code for processing data type B 

    def handler_for_type_C: 
     ... 
     #code for processing data type C 

    handler_map = {type_A: handler_for_type_A, 
       type_B: handler_for_type_B, 
       type_C: handler_for_type_C, 
       } 
    return handler_map(type) 

Однако, это кажется довольно неэффективным, так как я буду называть get_handler_by_type часто и каждый раз, когда он вызывается, словарь будет построен заново.

Я знаю, что я мог бы сделать это вместо того, чтобы:

def handler_for_type_A: 
    ... 
    #code for processing data type A 

def handler_for_type_B: 
    ... 
    #code for processing data type B 

def handler_for_type_C: 
    ... 
    #code for processing data type C 

handler_map = {type_A: handler_for_type_A, 
       type_B: handler_for_type_B, 
       type_C: handler_for_type_C, 
      } 

def get_handler_by_type(type, handler_map = handler_map): 
    return handler_map(type) 

Но это довольно уродливые, на мой взгляд. Потому что у меня есть handler_for_type_Xs и handler_map, которые загрязняют глобальное пространство. Есть ли способ сделать это как эффективно, так и изящно?

Спасибо за любые ввода.

+0

Что случилось с 'handler_for_type_A' i n глобальное пространство имен? –

+0

Если нет _lot_ обработчиков, вряд ли это будет горячая точка. –

+0

@WaleedKhan: Как указал гниблер, будет много обработчиков. На самом деле я пишу программу, которая анализирует пакеты Bluetooth Low Energy. Существуют разные типы заголовков, и каждая полезная нагрузка, связанная с заголовком, должна обрабатываться по-разному. Я не хочу, чтобы все эти обработчики отображались в глобальном пространстве. – foresightyj

ответ

1

Этот путь будет инкапсулировать:

def _handler_helper(): 
    def fna(): 
     print "a" 
     pass 

    def fnb(): 
     print "b" 
     pass 

    m = {"a":fna,"b":fnb} 
    return lambda x:m[x] 

get_handler_by_type = _handler_helper() 

Вы можете использовать def, если вы хотите иметь строку документации, но это работает.

Другим вариантом может быть, чтобы иметь более объектно-ориентированного подхода:

class _HandlerHelper: 
    def fna(self): 
     print 'a' 

    def fnb(self): 
     print 'b' 

    # __call__ is a magic method which lets you treat the object as a function 
    def __call__(self, fn): 
     return getattr(self, 'fn' + fn) 

get_handler_by_type = _HandlerHelper() 
+0

Вы можете просто вернуть m.get' –

+0

@gnibbler, который изменит подпись функции. – cwallenpoole

+0

@cwallnpoole Мне тоже нравится этот ответ. Я не привык думать о возврате функции вызывающему. Я буду помнить такие трюки в будущем. – foresightyj

2

Одним из способов является смотреть обработчик динамически (если у вас есть постоянное соглашение об именовании)

return vars()['handler_for_'+type] 

Другой способ для сохранения карты в качестве атрибута функции

def get_handler_by_type(type): 
    def handler_for_type_A: 
     ... 
     #code for processing data type A 

    def handler_for_type_B: 
     ... 
     #code for processing data type B 

    def handler_for_type_C: 
     ... 
     #code for processing data type C 

    if not hasattr(get_handler_by_type, 'handler_map'): 
     get_handler_by_type.handler_map = {'type_A': handler_for_type_A, 
       'type_B': handler_for_type_B, 
       'type_C': handler_for_type_C, 
       } 

    return get_handler_by_type.handler_map[type] 
+0

Это действительно элегантно и эффективно. Большое спасибо. – foresightyj

Смежные вопросы