'How to write string based dynamic function dispatch in python from within a class?
I want to dynamically determine function dispatch in my python code. Like so : https://docs.python.org/3/faq/programming.html#how-do-i-use-strings-to-call-functions-methods
I build a dispatch dictionary wherein:
dispatch = {'foo' : foo_function, 'bar': bar:function}
And then from within code, I can call the appropriate function based on my data
string by saying:
dispatch[data]()
So far so good. My issue is I want this functionality inside a class accessible to it's methods:
class Demo(object):
""" Demonstrate the issue
"""
dispatch = {'foo' : self.call_foo, 'bar': self.call_bar}
def parse_component(self, data, some_param):
self.__class__.dispatch[data](self, some_param)
def call_foo(self, some_param):
""" Do some intelligent work here"""
pass
def call_bar(self, some_param):
""" Do some intelligent work here"""
pass
The problem is that dispatch table is a class variable and does not have a notion of the instance methods self.call_foo and self.call_bar. I tried using get_attr :
class Demo(object):
dispatch = {'foo': getattr(Demo, 'call_foo')}
I get a NameError on Demo with this. It does not recognize the class name from within the class which I guess makes sense.
Other than making dispatch another instance method, is there any other way to do this? Ideally dispatch should be a class variable/method since it is constant to the class.
Solution 1:[1]
The functions Demo.call_foo
and Demo.call_bar
are functions which take in an instance self
and some_param
. When you create an instance of Demo
, e.g. d = Demo()
, those functions now become bound methods where the self
parameter is already passed for you. But the other form still exists, so you can call instance methods with ClassName.method(instance, ...)
. For example:
class Demo:
def call_foo(self):
print("called foo")
Calling it both ways works:
>>> d = Demo()
>>> Demo.call_foo(d)
called foo
>>> d.call_foo()
called foo
This is relevant to your question because inside the class definition, you don't have an instance self
to use, but you can refer to the functions directly. Since they are functions defined in the class scope, they can be referenced directly like any other class attribute.
But like we've seen above, you can pass the instance along to the function. You're already doing that in parse_component
. So the only problem with your current code is that you tried to use self
to reference the methods. But since the dict is defined in the class scope, you can just refer to them by name:
class Demo:
def parse_component(self, data, some_param):
self.__class__.dispatch[data](self, some_param)
def call_foo(self, some_param):
print("called foo with", some_param)
def call_bar(self, some_param):
print("called bar with", some_param)
dispatch = {'foo' : call_foo, 'bar': call_bar}
And using it:
>>> d = Demo()
>>> d.parse_component("foo", 2)
called foo with 2
>>> d.parse_component("bar", 3)
called bar with 3
>>> Demo.parse_component(d, "foo", 4)
called foo with 4
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | alkasm |