hekevintran
hekevintran

Reputation: 23722

How do I execute a string containing Python code in Python?

How do I execute a string containing Python code in Python?


Editor's note: Never use eval (or exec) on data that could possibly come from outside the program in any form. It is a critical security risk. You allow the author of the data to run arbitrary code on your computer. If you are here because you want to create multiple variables in your Python program following a pattern, you almost certainly have an XY problem. Do not create those variables at all - instead, use a list or dict appropriately.

Upvotes: 493

Views: 528105

Answers (15)

Paul Baxter
Paul Baxter

Reputation: 1175

In my gcd program I ran into an issue because my gcd takes an unspecified number of arguments using *terms. So I take the users arguments and generate a string to execute in a function

import argparse

# GCD
def gcd(*values: tuple) -> int:
    terms:list[int] = list(values)
    shift: int = 0
    numEven:int = 0
    numOdd: int = 0
    smallindex: int = -1

    # Step 1 count number of even and odd
    SZ:int = len(terms)
    if SZ == 1:
        return terms[0]

    while True:
        i:int
        numEven:int = 0
        numOdd = 0
        smallindex = -1
        for i in range(SZ):
       
            if terms[i] == 0:
                continue

            if terms[i] & 1:
                numOdd += 1
            else:
                numEven += 1

            if smallindex < 0 or terms[i] < terms[smallindex]:
                smallindex = i

        # check for exit
        if numEven + numOdd == 1:
            break

        # If everything in terms is even, divide everything in terms by 2, and then multiply the final answer by 2 at the end.
        if numOdd == 0:

            shift += 1
            for i in range(SZ):
                if terms[i] == 0:
                    continue

                terms[i] >>= 1
            continue
        
        # If some numbers in terms  are even and some are odd, divide all the even numbers by 2.
        if numEven > 0 and numOdd > 0:
            for i in range(SZ):
                if terms[i] == 0:
                    continue

                if terms[i] & 1 == 0:
                    terms[i] >>= 1
            
            continue

        # If every number in terms is odd, then choose an arbitrary element of terms and call it k.Replace every other element, say n, with | n−k | / 2.
        if numEven == 0:
            for i in range(SZ):
                if i == smallindex or terms[i] == 0:
                    continue

                terms[i] = abs(terms[i] - terms[smallindex]) >> 1

    # only one remaining element multiply the final answer by 2s at the end.
    for i in range(SZ):
        if terms[i] == 0:
            continue

        return terms[i] << shift    

    return 0

def call_fun(fun:str, args:list) ->any:
    fun_str:str = fun + '('
    argc: int = len(args)
    for i in range(argc):
        fun_str += str(args[i])
        if i < argc -1:
            fun_str += ', '
    fun_str += ')'
    return eval(fun_str)

# main entry point
def main() -> None:
    
    # create parser
    desc_str = "This program calculates the GCD of integers"
    parser = argparse.ArgumentParser(prog='gcd', description=desc_str)
    parser.add_argument(dest="terms", type=int, nargs='+', help='terms to calculate gcd of')

    # parse args
    try:
        args = parser.parse_args()

    except argparse.ArgumentError:
        print('Argument error. Unable to parse arguments.')
        parser.print_help()
        return

    except argparse.ArgumentTypeError:
        print('Argument type error. Unable to parse arguments.')
        parser.print_help()
        return
    
    print(call_fun('gcd', args.terms))


# call main
if __name__ == '__main__':
    main()

Upvotes: 0

Brian
Brian

Reputation: 119211

For statements, use exec(string) (Python 3) or exec string (Python 2):

>>> my_code = 'print("Hello world")'
>>> exec(my_code)
Hello world

When you need the value of an expression, use eval(string):

>>> x = eval("2+2")
>>> x
4

However, the first step should be to ask yourself if you really need to. Executing code should generally be the position of last resort: It's slow, ugly and dangerous if it can contain user-entered code. You should always look at alternatives first, such as higher order functions, to see if these can better meet your needs.

Upvotes: 467

user1767754
user1767754

Reputation: 25094

It's worth mentioning that exec's brother exists as well, called execfile, if you want to call a Python file. That is sometimes good if you are working in a third party package which have terrible IDE's included and you want to code outside of their package.

Example:

execfile('/path/to/source.py')

or:

exec(open("/path/to/source.py").read())

Upvotes: 14

shuvo
shuvo

Reputation: 1956

I tried quite a few things, but the only thing that worked was the following:

temp_dict = {}
exec("temp_dict['val'] = 10") 
print(temp_dict['val'])

output:

10

Upvotes: 7

Minions
Minions

Reputation: 5467

As the others mentioned, it's "exec" ..

but, in case your code contains variables, you can use "global" to access it, also to prevent the compiler to raise the following error:

NameError: name 'p_variable' is not defined

exec('p_variable = [1,2,3,4]')
global p_variable
print(p_variable)

Upvotes: 9

alan
alan

Reputation: 3534

eval and exec are the correct solution, and they can be used in a safer manner.

As discussed in Python's reference manual and clearly explained in this tutorial, the eval and exec functions take two extra parameters that allow a user to specify what global and local functions and variables are available.

For example:

public_variable = 10

private_variable = 2

def public_function():
    return "public information"

def private_function():
    return "super sensitive information"

# make a list of safe functions
safe_list = ['public_variable', 'public_function']
safe_dict = dict([ (k, locals().get(k, None)) for k in safe_list ])
# add any needed builtins back in
safe_dict['len'] = len

>>> eval("public_variable+2", {"__builtins__" : None }, safe_dict)
12

>>> eval("private_variable+2", {"__builtins__" : None }, safe_dict)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1, in <module>
NameError: name 'private_variable' is not defined

>>> exec("print \"'%s' has %i characters\" % (public_function(), len(public_function()))", {"__builtins__" : None}, safe_dict)
'public information' has 18 characters

>>> exec("print \"'%s' has %i characters\" % (private_function(), len(private_function()))", {"__builtins__" : None}, safe_dict)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1, in <module>
NameError: name 'private_function' is not defined

In essence you are defining the namespace in which the code will be executed.

Upvotes: 41

Brian
Brian

Reputation: 186

Ok .. I know this isn't exactly an answer, but possibly a note for people looking at this as I was. I wanted to execute specific code for different users/customers but also wanted to avoid the exec/eval. I initially looked to storing the code in a database for each user and doing the above.

I ended up creating the files on the file system within a 'customer_filters' folder and using the 'imp' module, if no filter applied for that customer, it just carried on

import imp


def get_customer_module(customerName='default', name='filter'):
    lm = None
    try:
        module_name = customerName+"_"+name;
        m = imp.find_module(module_name, ['customer_filters'])
        lm = imp.load_module(module_name, m[0], m[1], m[2])
    except:
        ''
        #ignore, if no module is found, 
    return lm

m = get_customer_module(customerName, "filter")
if m is not None:
    m.apply_address_filter(myobj)

so customerName = "jj" would execute apply_address_filter from the customer_filters\jj_filter.py file

Upvotes: 1

Caridorc
Caridorc

Reputation: 6641

Avoid exec and eval

Using exec and eval in Python is highly frowned upon.

There are better alternatives

From the top answer (emphasis mine):

For statements, use exec.

When you need the value of an expression, use eval.

However, the first step should be to ask yourself if you really need to. Executing code should generally be the position of last resort: It's slow, ugly and dangerous if it can contain user-entered code. You should always look at alternatives first, such as higher order functions, to see if these can better meet your needs.

From Alternatives to exec/eval?

set and get values of variables with the names in strings

[while eval] would work, it is generally not advised to use variable names bearing a meaning to the program itself.

Instead, better use a dict.

It is not idiomatic

From http://lucumr.pocoo.org/2011/2/1/exec-in-python/ (emphasis mine)

Python is not PHP

Don't try to circumvent Python idioms because some other language does it differently. Namespaces are in Python for a reason and just because it gives you the tool exec it does not mean you should use that tool.

It is dangerous

From http://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html (emphasis mine)

So eval is not safe, even if you remove all the globals and the builtins!

The problem with all of these attempts to protect eval() is that they are blacklists. They explicitly remove things that could be dangerous. That is a losing battle because if there's just one item left off the list, you can attack the system.

So, can eval be made safe? Hard to say. At this point, my best guess is that you can't do any harm if you can't use any double underscores, so maybe if you exclude any string with double underscores you are safe. Maybe...

It is hard to read and understand

From http://stupidpythonideas.blogspot.it/2013/05/why-evalexec-is-bad.html (emphasis mine):

First, exec makes it harder to human beings to read your code. In order to figure out what's happening, I don't just have to read your code, I have to read your code, figure out what string it's going to generate, then read that virtual code. So, if you're working on a team, or publishing open source software, or asking for help somewhere like StackOverflow, you're making it harder for other people to help you. And if there's any chance that you're going to be debugging or expanding on this code 6 months from now, you're making it harder for yourself directly.

Upvotes: 16

bheks
bheks

Reputation: 293

Remember that from version 3 exec is a function!
so always use exec(mystring) instead of exec mystring.

Upvotes: 23

gus
gus

Reputation: 119

You accomplish executing code using exec, as with the following IDLE session:

>>> kw = {}
>>> exec( "ret = 4" ) in kw
>>> kw['ret']

4

Upvotes: 11

LGB
LGB

Reputation: 159

eval() is just for expressions, while eval('x+1') works, eval('x=1') won't work for example. In that case, it's better to use exec, or even better: try to find a better solution :)

Upvotes: 15

user36457
user36457

Reputation:

The most logical solution would be to use the built-in eval() function .Another solution is to write that string to a temporary python file and execute it.

Upvotes: 1

hekevintran
hekevintran

Reputation: 23722

In the example a string is executed as code using the exec function.

import sys
import StringIO

# create file-like string to capture output
codeOut = StringIO.StringIO()
codeErr = StringIO.StringIO()

code = """
def f(x):
    x = x + 1
    return x

print 'This is my output.'
"""

# capture output and errors
sys.stdout = codeOut
sys.stderr = codeErr

exec code

# restore stdout and stderr
sys.stdout = sys.__stdout__
sys.stderr = sys.__stderr__

print f(4)

s = codeErr.getvalue()

print "error:\n%s\n" % s

s = codeOut.getvalue()

print "output:\n%s" % s

codeOut.close()
codeErr.close()

Upvotes: 85

ryeguy
ryeguy

Reputation: 66851

Check out eval:

x = 1
print eval('x+1')
->2

Upvotes: 4

Pablo Santa Cruz
Pablo Santa Cruz

Reputation: 181270

Use eval.

Upvotes: 5

Related Questions