开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜