Reputation: 8386
I have a bunch of functions, some of them require a bar
parameter, some of them require a foo
parameter, some of them require neither, and some require both.
I am hoping to call all of these functions from the same location, as the function is referenced from a variable.
The possible solutions I have found is:
I don't believe #1 will work, but I know that #2 will. Is there a native (not using a library) way for me to do this?
As an example:
functions = [lambda foo: foo.do_something(),
lambda bar: bar.do_something_else(),
lambda foo, bar: foo.something_with_bar(bar),
lambda: do_another_task()
]
for function in functions:
//call goes here
Note: I actually have many, many functions that I want to call with these parameters, and they aren't all stored nicely in an array. I would prefer if I could do it without changing the functions themselves.
Upvotes: 1
Views: 170
Reputation: 64318
You might be better off storing a lambda expression in a variable, instead of the underlying function, and binding your arguments in the lambda. Something like:
foo = 'foo'
bar = 'bar'
if funcname == 'a':
func = a # a takes no args
elif funcname == 'b':
func = lambda: bb(bar=bar) # bb takes bar
elif funcname == 'c':
func = lambda: ccc(foo=foo) # ccc takes foo
# call it, uniformly
func()
A similar approach would be to "de-bind":
if funcname == 'a':
func = lambda foo, bar: a() # don't pass foo and bar
elif funcname == 'b':
func = lambda foo, bar: bb(bar=bar) # don't pass foo
elif funcname == 'c':
func = lambda foo, bar: ccc(foo=foo) # don't pass bar
# call it, uniformly
func(foo, bar)
Furthermore, if you want to refactor your code to make it more elegant and object-oriented, define an interface and facade implementations:
class FooBarInterface(object):
def f(self, foo, bar):
raise NotImplementedError
class A(FooBarInterface):
def f(self, foo, bar):
return a()
class B(FooBarInterface):
def f(self, foo, bar):
return bb(bar=bar)
class C(FooBarInterface):
def f(self, foo, bar):
return ccc(foo=foo)
if funcname == 'a':
obj = A()
elif funcname == 'b':
obj = B()
elif funcname == 'c':
obj = C()
# call it, uniformly
obj.f()
And please don't use introspection. It would make your code way more complicated than need be.
Upvotes: 3
Reputation: 13279
No way to do it natively unless you can edit the functions themselves, if you have you could have
def func_a(**kwargs):
foo = kwargs['foo']
# or even:
foo = kwargs.get('foo', None) # in case foo wasn't passed the the function
...
def func_b(**kwargs):
bar = kwargs.get('bar', None)
...
With the functions setup that way you can pass any key word arguments you like.
Upvotes: 0