Get functions called in a Python expression
I have a database that holds the name of Python functions and 开发者_如何学Pythona string for their code. I want the user to be able to enter a Python code and see the result. The problem is that I need to know the names of the functions they call in order to retrieve the code from the database. For instance, if they enter cubic_fit(1, 2, get_data())
, I need a way to get the function names cubic_fit
and get_data
. Is there a good way to do this?
The built-in function compile will do that for you exactly:
>>> compile("cubic_fit(1, 2, get_data())", '<string>', 'eval').co_names
('cubic_fit', 'get_data')
And it is safe to run. No code is actually being executed just compiled.
A quick example to you started. Note that you'll be expecting valid python semantics for this to work.
You can extend this to also parse your arguments...
import token, tokenize, StringIO
def extract_names(src):
rawstr = StringIO.StringIO(unicode(src))
tokens = tokenize.generate_tokens(rawstr.readline)
for i, item in enumerate(tokens):
toktype, toktext, (srow,scol), (erow,ecol), line = item
if token.tok_name[toktype] == 'NAME':
print 'name:', toktext
extract_names("cubic_fit(1, 2, get_data())")
# --> output:
# name: cubic_fit
# name: get_data
If you just want the names, then the compile() and co_names method will work best.
You also might take advantage of the capability of eval() to use any mapping object as its locals parameter. You could create a mapping object to look up and compile the objects from your database as needed by eval().
Example:
class LookitUp(object):
def __init__(self):
# simulate some data
self.d = { "foo": "def foo(a):\n return a + 2"}
def __getitem__(self,key):
localdict = {}
c = compile(self.d.get(key,""),"<string>","exec")
eval(c,globals(),localdict)
return localdict[key]
d = LookitUp()
def bar(a):
return a - 1
print "foo from database :",eval("foo(3)",globals(), d)
print "bar from globals():",eval("bar(3)",globals(), d)
print "foo(bar(3)) :",eval("foo(bar(3))",globals(), d)
Result:
foo from database : 5
bar from globals(): 2
foo(bar(3)) : 4
You may need to modify based on what your source in the database looks like, but it's a place to start.
精彩评论