Note, the functions should be functions, not strings, for this implementation to work
If you want to return the function called with a set of kwargs
, you're pretty close. I would use a positional argument for func
, then you can pass kwargs
into func
, which is a bit more explicit:
def myfunc(func, **kwargs):
return func(**kwargs)
Then, you could wrap each pair of func, **kwargs
as tuples, and do a for loop:
# This would be called like
somelist = [(np.random.normal, { 'loc' : 0 , 'scale' : 1 , 'size' : 7 }),
(np.random.uniform , { 'low' : 0 , 'high' : 1 , 'size' : 7 })]
results = []
# append results to a list
for func, kwargs in somelist:
results.append(myfunc(func, **kwargs))
By doing it this way, you don't have to worry about what you name any of your variables, and it's a bit more readable. You know that the loop will be dealing with pairs of items, in this case func, kwarg
pairs, and your function can handle those explicitly
Handling the string calls
So there are a few ways to accomplish this task that are a bit more tricky, but overall shouldn't be horrible. You'll need to modify myfunc
to handle the function name:
# func is now a string, unlike above
def myfunc(func, **kwargs):
# function will look like module.class.function
# so split on '.' to get each component. The first will
# be the parent module in global scope, and everything else
# is collected into a list
mod, *f = func.split('.') # f is a list of sub-modules like ['random', 'uniform']
# func for now will just be the module np
func = globals().get(mod)
for cls in f:
# get each subsequent level down, which will overwrite func to
# first be np.random, then np.random.uniform
func = getattr(func, cls)
return func(**kwargs)
The reason I'm using globals().get(mod)
is a) I'm assuming you might not always be using the same module, and b) calling a renamed import from sys.modules
will yield a KeyError
, which isn't what you want:
import sys
import numpy as np
sys.modules['np'] # KeyError
sys.modules['numpy']
# <module 'numpy.random' from '/Users/mm92400/anaconda3/envs/new36/lib/python3.6/site-packages/numpy/random/__init__.py'>
# globals avoids the naming conflict
globals()['np']
# <module 'numpy.random' from '/Users/mm92400/anaconda3/envs/new36/lib/python3.6/site-packages/numpy/random/__init__.py'>
Then getattr(obj, attr)
will return each subsequent module:
import numpy as np
getattr(np, 'random')
# <module 'numpy.random' from '/Users/mm92400/anaconda3/envs/new36/lib/python3.6/site-packages/numpy/random/__init__.py'>
# the dotted access won't work directly
getattr(np, 'random.uniform')
# AttributeError
So, in total:
import numpy as np
func, kwargs = ('np.random.normal', { 'loc' : 0 , 'scale' : 1 , 'size' : 7 })
myfunc(func, **kwargs)
array([ 0.83276777, 2.4836389 , -1.07492873, -1.20056678, -0.36409906,
-0.76543554, 0.90191746])
And you can just extend that to the code in the first section