[python] Python function pointer

I have a function name stored in a variable like this:

myvar = 'mypackage.mymodule.myfunction'

and I now want to call myfunction like this

myvar(parameter1, parameter2)

What's the easiest way to achieve this?

This question is related to python function-pointers

The answer is


Easiest

eval(myvar)(parameter1, parameter2)

You don't have a function "pointer". You have a function "name".

While this works well, you will have a large number of folks telling you it's "insecure" or a "security risk".


Why not store the function itself? myvar = mypackage.mymodule.myfunction is much cleaner.


def f(a,b):
    return a+b

xx = 'f'
print eval('%s(%s,%s)'%(xx,2,3))

OUTPUT

 5

eval(compile(myvar,'<str>','eval'))(myargs)

compile(...,'eval') allows only a single statement, so that there can't be arbitrary commands after a call, or there will be a SyntaxError. Then a tiny bit of validation can at least constrain the expression to something in your power, like testing for 'mypackage' to start.


I ran into a similar problem while creating a library to handle authentication. I want the app owner using my library to be able to register a callback with the library for checking authorization against LDAP groups the authenticated person is in. The configuration is getting passed in as a config.py file that gets imported and contains a dict with all the config parameters.

I got this to work:

>>> class MyClass(object):
...     def target_func(self):
...         print "made it!"
...    
...     def __init__(self,config):
...         self.config = config
...         self.config['funcname'] = getattr(self,self.config['funcname'])
...         self.config['funcname']()
... 
>>> instance = MyClass({'funcname':'target_func'})
made it!

Is there a pythonic-er way to do this?


It's much nicer to be able to just store the function itself, since they're first-class objects in python.

import mypackage

myfunc = mypackage.mymodule.myfunction
myfunc(parameter1, parameter2)

But, if you have to import the package dynamically, then you can achieve this through:

mypackage = __import__('mypackage')
mymodule = getattr(mypackage, 'mymodule')
myfunction = getattr(mymodule, 'myfunction')

myfunction(parameter1, parameter2)

Bear in mind however, that all of that work applies to whatever scope you're currently in. If you don't persist them somehow, you can't count on them staying around if you leave the local scope.


modname, funcname = myvar.rsplit('.', 1)
getattr(sys.modules[modname], funcname)(parameter1, parameter2)