Building a function call?
3 answers - 1128 bytes -

Francois De Serres wrote:
Having a string: "dothat"
and a tuple: (x, y)
1. What's the best way to build a function call like: dothat(x,y)?
Assuming dothat is def'd in the same module,
2. is: eval("dothat(x,y)", None, (('x', 100), ('y', 200)))
the right way to have it executed?
If dothat is def'd in another module:
3. what would be the right way to initialize the globals to pass to
eval ?
No, none of this is a good place to use eval.
aString = "dothat"
atuple = (x, y)
If aString is the name of a function in the current module:
globals()[aString](*aTuple)
If aString is a function in another module:
import otherModule
vars(otherModule)[aString](*aTuple)
and if you don't know the name of the module in advance:
otherModule = __import__(Module)
vars(otherModule)[aString](*aTuple)
Better still, collect all the functions you expect to be callable in this
way together in a dictionary and then you can be sure that you only call
something you intended to be callable.
No.1 | | 1007 bytes |
| 
Duncan Booth wrote:
Francois De Serres wrote:
>>Having a string: "dothat"
>>and a tuple: (x, y)
>>1. What's the best way to build a function call like: dothat(x,y)?
>>
>>Assuming dothat is def'd in the same module,
>>2. is: eval("dothat(x,y)", None, (('x', 100), ('y', 200)))
>>the right way to have it executed?
>>
>>If dothat is def'd in another module:
>>3. what would be the right way to initialize the globals to pass to
>>eval ?
No, none of this is a good place to use eval.
aString = "dothat"
atuple = (x, y)
If aString is the name of a function in the current module:
globals()[aString](*aTuple)
If aString is a function in another module:
import otherModule
vars(otherModule)[aString](*aTuple)
Ick! Please:
getattr(otherModule, aString)(*aTuple)
No.2 | | 1774 bytes |
| 
Wed, 13 Jul 2005 06:16:54 -0700, Robert Kern wrote:
Duncan Booth wrote:
>Francois De Serres wrote:
>
Having a string: "dothat"
and a tuple: (x, y)
1. What's the best way to build a function call like: dothat(x,y)?
[snip]
>No, none of this is a good place to use eval.
[snip]
>import otherModule
>vars(otherModule)[aString](*aTuple)
Ick! Please:
getattr(otherModule, aString)(*aTuple)
, remember that functions are first class objects in Python. Instead of
passing around the function name as a string, pass around a reference to
the function itself. Something like this:
def dothis(x,y):
return x-y
def dothat(x,y):
return x+y
somefunction = dothis
somefunction(3, 2)
=returns 1
somefunction = dothat
somefunction(3, 2)
=returns 5
allfunctions = [dothis, dothat]
for func in allfunctions:
print func(3, 2)
=prints 1 then 5
If you want to collect user-supplied strings and use them to find a
function, you could use eval (terribly risky and unsafe), or you could do
something like this:
funcnames = {}
for func in allfunctions:
funcnames[funcname__] = func
F = raw_input("Enter the name of a function: ")
try:
funcnames[F](3, 2)
except KeyError:
print "Function '%s' not found!" % F
In my humble opinion, people muck about with eval, locals and globals far
too often. It is unclear, hard to maintain, and frequently a security
risk. These confusing, unsafe practices can usually be avoided by
remembering that functions are first class objects just like ints, strings
and lists.
No.3 | | 2658 bytes |
| 
Steven D'Aprano wrote:
Wed, 13 Jul 2005 06:16:54 -0700, Robert Kern wrote:
>
>>Duncan Booth wrote:
>
>>
Francois De Serres wrote:
Having a string: "dothat"
and a tuple: (x, y)
1. What's the best way to build a function call like: dothat(x,y)?
>[snip]
No, none of this is a good place to use eval.
>[snip]
import otherModule
vars(otherModule)[aString](*aTuple)
>>Ick! Please:
>>getattr(otherModule, aString)(*aTuple)
>
>>
>
>
>, remember that functions are first class objects in Python. Instead of
>passing around the function name as a string, pass around a reference to
>the function itself. Something like this:
>
>
>def dothis(x,y):
return x-y
>
>def dothat(x,y):
return x+y
>
>somefunction = dothis
>somefunction(3, 2)
returns 1
>
>somefunction = dothat
>somefunction(3, 2)
returns 5
>
>allfunctions = [dothis, dothat]
>for func in allfunctions:
print func(3, 2)
prints 1 then 5
>
>If you want to collect user-supplied strings and use them to find a
>function, you could use eval (terribly risky and unsafe), or you could do
>something like this:
>
>funcnames = {}
>for func in allfunctions:
funcnames[funcname__] = func
>F = raw_input("Enter the name of a function: ")
>try:
funcnames[F](3, 2)
>except KeyError:
print "Function '%s' not found!" % F
>
>
>In my humble opinion, people muck about with eval, locals and globals far
>too often. It is unclear, hard to maintain, and frequently a security
>risk. These confusing, unsafe practices can usually be avoided by
>remembering that functions are first class objects just like ints, strings
>and lists.
>
>
>
I'm aware of the functions being objects, but I really need to work with
strings in that case.
Still, I was not aware that eval() was such a 'rogue', it's not said in
the manuals ;)
Many thanks!
F.