foresightyj
foresightyj

Reputation: 2106

How to encapsulate handlers in an efficient manner in Python?

I am making up a handler to handle different types of data. Here is my current solution:

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)

However, this seems quite inefficient as I will call get_handler_by_type frequently and every time it gets called, the dictionary will be constructed again.

I know I could do this instead:

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)

But this is pretty ugly in my opinion. Because I have handler_for_type_Xs and handler_map that are polluting the global space. Is there a way of doing this both efficiently and elegantly?

Thanks for any inputs.

Upvotes: 0

Views: 85

Answers (2)

cwallenpoole
cwallenpoole

Reputation: 82008

This way will encapsulate it:

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()

You may want to use def if you want to have a docstring, but this works.

Another option might be to have a more OOP approach:

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()

Upvotes: 1

John La Rooy
John La Rooy

Reputation: 304147

One way is to look the handler up dynamically (if you have a consistent naming convention)

return vars()['handler_for_'+type]

Another way is to store the map as an attribute of the function

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]

Upvotes: 2

Related Questions