38

Some days ago I was searching on the net and I found an interesting article about python dictionaries. It was about using the keys in the dictionary to call a function. In that article the author has defined some functions, and then a dictionary with key exactly same as the function name. Then he could get an input parameter from user and call the same method (something like implementing case break) After that I realised about the same thing but somehow different. I want to know how I can implement this. If I have a function:

def fullName( name = "noName", family = "noFamily" ):
    return name += family

And now if I have a string like this:

myString = "fullName( name = 'Joe', family = 'Brand' )"

Is there a way to execute this query and get a result: JoeBrand
For example something I remember is that we might give a string to exec() statement and it does it for us. But I’m not sure about this special case, and also I do not know the efficient way in Python. And also I will be so grateful to help me how to handle that functions return value, for example in my case how can I print the full name returned by that function?

user435245
  • 859
  • 4
  • 16
  • 28
  • 2
    you function is gonna return None...use + instead of += – Ant Nov 09 '10 at 09:41
  • 1
    To accomplish this, use: getattr(myString, 'fullName')(name='Joe', family='Brand') [see duplicate question linked at top of page] – Stew Jan 08 '15 at 18:29
  • [Note: getattr() is used by the top answer on the question that this post duplicates, but is not mentioned below. I thought it would be helpful to appear on this page itself, so am bending the convention against answering questions in comments.] – Stew Jan 08 '15 at 18:29

3 Answers3

51

This does not exactly answer your question, but maybe it helps nevertheless:

As mentioned, eval should be avoided if possible. A better way imo is to use dictionary unpacking. This is also very dynamic and less error prone.

Example:

def fullName(name = "noName", family = "noFamily"):
    return name + family

functionList = {'fullName': fullName}

function = 'fullName'
parameters = {'name': 'Foo', 'family': 'Bar'}

print functionList[function](**parameters)
# prints FooBar

parameters = {'name': 'Foo'}
print functionList[function](**parameters)
# prints FoonoFamily
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
41

You could use eval():

myString = "fullName( name = 'Joe', family = 'Brand' )"
result = eval(myString)

Beware though, eval() is considered evil by many people.

Frédéric Hamidi
  • 258,201
  • 41
  • 486
  • 479
  • Thanks in advance, but does it return any value from the function in case I store it in a variable? – user435245 Nov 09 '10 at 08:54
  • Yes, it does. See my updated answer. – Frédéric Hamidi Nov 09 '10 at 08:55
  • 3
    Better answer: http://stackoverflow.com/questions/3061/calling-a-function-from-a-string-with-the-functions-name-in-python – Framester May 01 '12 at 14:43
  • 2
    @Framester No, that is not a better answer, it is an answer for a different case. This is asking how to call a function, with no object whatsoever. The answer you're promoting is about calling an object's method. – gdvalderrama Jan 16 '18 at 12:33
  • I think that however this is a better answer since it avoids `eval()`: https://stackoverflow.com/a/22021058/9024698. If I am not wrong, it is also the answer of @kirbyfan below (https://stackoverflow.com/a/16683842/9024698). – Outcast Oct 24 '18 at 16:57
12

I know this question is rather old, but you could do something like this:

argsdict = {'name': 'Joe', 'family': 'Brand'}
globals()['fullName'](**argsdict)

argsdict is a dictionary of argument, globals calls the function using a string, and ** expands the dictionary to a parameter list. Much cleaner than eval. The only trouble lies in splitting up the string. A (very messy) solution:

example = 'fullName(name=\'Joe\',family=\'Brand\')'
# Split at left parenthesis
funcname, argsstr = example.split('(')
# Split the parameters
argsindex = argsstr.split(',')
# Create an empty dictionary
argsdict = dict()
# Remove the closing parenthesis
# Could probably be done better with re...
argsindex[-1] = argsindex[-1].replace(')', '')
for item in argsindex:
    # Separate the parameter name and value
    argname, argvalue = item.split('=')
    # Add it to the dictionary
    argsdict.update({argname: argvalue})
# Call our function
globals()[funcname](**argsdict)
kirbyfan64sos
  • 10,377
  • 6
  • 54
  • 75
  • The one and only solution. Should this code reside in a module, and that module would get reloaded after `fullName`'s code got changed, then the changes are effective in the next call to `fullName`. Felix Kling's answer doesn't have this property as the function is cached in `functionList`, and we won't even talk about how bad the `eval` idea is. – Daniel F Dec 18 '17 at 22:14