dinkelk
dinkelk

Reputation: 2786

How to compile text as a function using AST?

I need to compile an input string (from a database) as a function and run it. This is the method I currently use:

Say I already have this function defined:

def foo():
    print "Yo foo! I am a function!"

And the string I read in from the database says I should call this function:

string_from_db = "foo()"

I then form a function (whose name I can control) which returns the function I read in from the database:

my_func_string = "def doTheFunc():\n\t return " + string_from_db

Now I compile the string, and set it to a function name I use later for processing:

exec my_func_string
processor = doTheFunc

I can call it later by running processor() which exclaims: Yo foo! I am a function!

My Question: Above this piece of code there is a comment (left by a long lost developer):

    ###############################################################
    # The following method for getting a function out of the text #
    # in the database could potentially be replaced by using      #
    # Python's ast module to obtain an abstract syntax tree and   #
    # put it inside of a function node                            #
    ###############################################################

I'd like to know more about this "potential replacement." I have taken a look at AST, but I am very confused on how it can help me do what I am already doing with the code above.

  1. How can I accomplish the same thing using AST? Or where can AST help me in this process?
  2. Is the implementation using AST better, and why?

Upvotes: 6

Views: 3052

Answers (1)

iabdalkader
iabdalkader

Reputation: 17312

AST is a much safer choice when evaluating untrusted code, that could contain malicious instructions, eval or exec can execute any expression, while AST on the other hand, allows you to parse and validate the expression yourself, or execute a limited expression using ast.literal_eval, sort of like a sandbox, which allows only strings, lists, numbers and a few other things. This is just a simple example:

import ast
a = ast.literal_eval("[1,2,3,4]") //evaluate an expression safely.

Another example that parses a string into an AST:

import ast
source = '2 + 2'
node = ast.parse(source, mode='eval')
ast.dump(node)

This prints:

Expression(body=BinOp(left=Num(n=2), op=Add(), right=Num(n=2)))

There's a very good tutorial here and also the documentation

Upvotes: 5

Related Questions