views:

128

answers:

4

Is there a way to pass a list as a function argument to eval() Or do I have to convert it to a string and then parse it as a list in the function?

My simple example looks like:

 eval("func1(\'" + fArgs + "\')")

I'm just not sure if there is a better way of taking fArgs as a list instead of a string

Note: The list is provided from a JSON response

EDIT: Ok heres a bit more of my class so theres a better understanding of how I'm using eval

def test(arg):
     print arg

#Add all allowed functions to this list to be mapped to a dictionary     
safe_list = ['test']
safe_dict = dict([ (k, locals().get(k, None)) for k in safe_list ])

class Validate:
     def __init__(self, Value, fName, fArgs):
     eval(fName + "(\'" + fArgs + "\')", {"__builtins__":None},safe_dict)

I may be wrong in thinking this, but to my understanding this is a safe use of eval because the only fuctions that can be called are the ones that are listed in the safe_list dictionary. The function to be run and the arguments for that function are being extracted out of a JSON object. The arguments are to be structured as a list, Will joining the list together with ", " be interpreted as actual arguments or just a single argument?

+2  A: 

Specifying parameters the following way works:

root@parrot$ more test.py
def func1(*args):
        for i in args:
                print i

l = [1,'a',9.1]
func1(*l)

root@parrot$ python test.py
1
a
9.1

so, no direct need for eval(), unless I'm misunderstanding something.

Vinko Vrsalovic
+1: Usually when you need to use `eval` you're probably going about it the wrong way. Passing the list by reference as suggested here is preferred and safer in the long run.
jathanism
Well whats being done, is the function name and arguments are held in a json string that I'm parsing, and I want it to run the function and arguments given in the json. I've limited the global and local functions to only whats in a specified dictionary.
whatWhat
Why don't you create a dictionary of functions referenced by their name (or some code) then? You can call the appropriate function with `functions['some_func']()`.
Dana the Sane
This is also more secure since it restricts the number of local calls that can be made to those you pick.
Dana the Sane
If you reject Dana's approach as well, eval can be used like eval("func1").__call__(*l)
Vinko Vrsalovic
+5  A: 

If you're using Python 2.6.x, then you should be able to use the json module (see py doc 19.2). If not, then there is python-json available through the python package index. Both of these packages will provide a reader for parsing JSON data into an appropriate Python data type.

For your second problem of calling a function determined by a message, you can do the following:

def foo():
    print 'I am foo!'
def bar():
    pass
def baz():
    pass

funcs = {'func_a':foo, 'func_b':bar, 'func_c':baz}

funcs['func_a']()

This approach can be a bit more secure than eval because it prevents 'unsafe' python library functions from being injected into the JSON. However, you still need to be cautious that the data supplied to your functions can't be manipulated to cause problems.

Dana the Sane
Excellent alternative!
jathanism
A: 

The others have a good point, that you shouldn't be using eval. But, if you must:

eval("func1(%s)" % ", ".join(fArgs))

will call the function with all the arguments in the list. This:

eval("func1([%s])" % ", ".join(fArgs))

will call it with the list of arguments in just one argument. Maybe you even want this?

eval("func1([%s])" % ", ".join(map(eval, fArgs)))

which would eval the arguments as well?

Claudiu
+1  A: 

Using a library to parse JSON input may be a better approach than eval, something like:

import json
func1(json.loads(fArgs))

Assert-ing that user input is correct would be a good idea, too.

ngn
I'm not using eval to parse json, the json itself holds some data like{ "function_name":"add", "Function_args": ["3", "1"]}I'd need to use eval to run the add function with the arguments of 3 and 1.
whatWhat