Building a function call?

Steven D'Aprano steve at REMOVETHIScyber.com.au
Wed Jul 13 09:55:28 EDT 2005


On 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)


Or, 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[func.__name__] = 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.



-- 
Steven.





More information about the Python-list mailing list