tags:

views:

776

answers:

6

Hi there,

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?

+1  A: 

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".

S.Lott
"insecure": If myvar comes from user input, yes :)
Federico Ramponi
They'd be "right".
Derrick Turk
...and those large number of folks are right.
Triptych
Aside from security issues, I get a "NameError: name 'mypackage' is not defined", while I can import modules from there going the "normal" way. And: of course, the string that shall be evaluated is fixed and not changed by the user.
schneck
@schneck, then why would it possibly have to be a string?
Mike Graham
@schneck: If eval('the string') does not produce the correct function, then your question is incomplete. You've omitted something crucial. You might try posting something that *does* work along with the detailed error message of what doesn't work.
S.Lott
@Derrick Turn, @Truptych: They'd be right only if the string came from a malicious sociopath. User input from unauthenticated people on the internet is likely to involve malicious sociopaths. Most everything else does not generally involve malicious sociopaths, reducing the security risk to exactly the same risk as someone deleting all the source code for the application.
S.Lott
It's only insecure if the data comes from external sources. If myvar is defined in your app, it's no less secure that directly calling the function.
Bryan Oakley
@Mike Graham: It must be a string because at the place where it is defined, the application does not know the desired function, since it's a generic app.
schneck
@schneck, I don't understand what you mean by "since it's a generic app" could mean here. If you have defined this as a string literal, you already know enough about it that you don't need to do so.
Mike Graham
Given the ability to run any functions given in `myvar`, why worry about `eval`?
KennyTM
@Mike Graham: I thought about that and I think you're right; I should reference a real function name rather than by a string.
schneck
+5  A: 
funcdict = {
  'mypackage.mymodule.myfunction': mypackage.mymodule.myfunction,
    ....
}

funcdict[myvar](parameter1, parameter2)
Ignacio Vazquez-Abrams
+1 Great answer.
TheMachineCharmer
Finally, your solution fits my needs best, thank you.
schneck
+3  A: 
def f(a,b):
    return a+b

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

OUTPUT

 5
TheMachineCharmer
why the downvote?
TheMachineCharmer
I'll give an upvote to counteract the downvote. It may not be the best solution, I do think it's a helpful answer since it shows a complete, working example.
Bryan Oakley
@ Bryan Oakley cheers!
TheMachineCharmer
+1  A: 
modname, funcname = myvar.rsplit('.', 1)
getattr(sys.modules[modname], funcname)(parameter1, parameter2)
Matt Anderson
+1  A: 

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

ironfroggy
+7  A: 

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.

AndrewBC