¿Cómo puedo ejecutar una cadena que contiene código Python en Python?


¿Cómo puedo ejecutar una cadena que contiene código Python en Python?

Author: SilentGhost, 2009-03-31

12 answers

Para las declaraciones, use exec(string) (Python 2/3) o exec string (Python 2):

>>> mycode = 'print "hello world"'
>>> exec(mycode)
Hello world

Cuando necesite el valor de una expresión, utilice eval(string):

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

Sin embargo, el primer paso debe ser preguntarse si realmente lo necesita. Ejecutar código debería ser generalmente la posición de último recurso: Es lento, feo y peligroso si puede contener código introducido por el usuario. Siempre debe mirar primero las alternativas, como las funciones de orden superior, para ver si pueden mejor satisfacer sus necesidades.

 246
Author: Brian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-16 08:22:07

En el ejemplo una cadena se ejecuta como código usando la función exec.

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()
 54
Author: hekevintran,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-03-31 16:14:38

Recuerde que desde la versión 3 exec es una función!
así que siempre use exec(mystring) en lugar de exec mystring.

 19
Author: bheks,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-11 02:12:50

eval y execson la solución correcta, y se pueden usar de una manera más segura.

Como se discute en el manual de referencia de Python y se explica claramente en este tutorial, las funciones eval y exec toman dos parámetros adicionales que permiten al usuario especificar qué funciones y variables globales y locales están disponibles.

Por ejemplo:

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

En esencia, está definiendo el espacio de nombres en el que se ejecutará el código.

 18
Author: alan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-30 18:28:58

eval() es solo para expresiones, mientras eval('x+1') funciona, eval('x=1') no funcionará, por ejemplo. En ese caso, es mejor usar exec, o incluso mejor: trate de encontrar una solución mejor:)

 11
Author: LGB,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-12 19:32:25

Puede ejecutar código usando exec, como en la siguiente sesión INACTIVA:

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

4
 9
Author: gus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-07-18 22:55:50

Evite exec y eval

Usar exec y eval en Python está muy mal visto.

Hay mejores alternativas

De la respuesta superior (énfasis mío):

Para las instrucciones, use exec.

Cuando necesite el valor de una expresión, use eval.

Sin embargo, el primer paso debe ser preguntarse si realmente lo necesita. Ejecutar código debería ser generalmente la posición de último recurso: Es lento, feo y peligroso si puede contener código introducido por el usuario. Siempre debe mirar primero las alternativas , como las funciones de orden superior, para ver si pueden satisfacer mejor sus necesidades.

De Alternativas a exec/eval?

Establecer y obtener valores de variables con los nombres en cadenas

[mientras que eval] funcionaría, generalmente no se aconseja usar nombres de variables que tengan un significado para el programa en sí.

En su lugar, es mejor utilizar un dict.

No es idiomático

De http://lucumr.pocoo.org/2011/2/1/exec-in-python / (subrayado mío)

Python no es PHP

No intente eludir los modismos de Python porque algún otro lenguaje lo hace de manera diferente. Los espacios de nombres están en Python por una razón y solo porque te da la herramienta exec no significa que debas usar esa herramienta.

Es peligroso

De http://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html (énfasis mío)

Así que eval no es seguro, incluso si se eliminan todos los globals y los builtins!

El problema con todos estos intentos de proteger eval() es que son listas negras. Eliminan explícitamente cosas que podrían ser peligrosas. Esa es una batalla perdida porque si solo queda un objeto fuera de la lista, puedes atacar el sistema.

So, puede eval ser seguro? Es difícil de decir. En este punto, mi mejor conjetura es que no puedes hacer ningún daño si no puedes usar guiones bajos dobles, así que tal vez si excluyes cualquier cadena con guiones bajos dobles estás a salvo. Posiblemente...

Es difícil leer y entender{[14]]}

De http://stupidpythonideas.blogspot.it/2013/05/why-evalexec-is-bad.html (énfasis mío):

Primero, exec hace que sea más difícil para los seres humanos leer su código . Con el fin de averiguar lo que está sucediendo, no solo tengo que leer su código, Tengo que leer su código, averiguar qué cadena va a generar, luego leer ese código virtual. Entonces, si estás trabajando en un equipo, o publicando software de código abierto, o pidiendo ayuda en algún lugar como StackOverflow, estás haciendo más difícil que otras personas te ayuden. Y si hay alguna posibilidad de que vayas a depurar o expandir este código en 6 meses a partir de ahora, lo estás haciendo más difícil para ti mismo directamente.

 8
Author: Caridorc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:18:15

Echa un vistazo eval :

x = 1
print eval('x+1')
->2
 3
Author: ryeguy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-03-31 16:14:05

La solución más lógica sería usar la función integrada eval().Otra solución es escribir esa cadena en un archivo temporal de python y ejecutarla.

 3
Author: John T,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-03-31 16:15:10

Use eval.

 1
Author: Pablo Santa Cruz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-03-31 16:13:49

Ok .. Sé que esto no es exactamente una respuesta, pero posiblemente una nota para la gente mirando esto como yo estaba. Quería ejecutar código específico para diferentes usuarios / clientes, pero también quería evitar la exec / eval. Inicialmente busqué almacenar el código en una base de datos para cada usuario y hacer lo anterior.

Terminé creando los archivos en el sistema de archivos dentro de una carpeta 'customer_filters' y usando el módulo' imp', si no se aplicaba ningún filtro para ese cliente, solo llevaba el

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" ejecutaría apply_address_filter desde el customer_filters\jj_filter.py file

 0
Author: Brian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-12 13:00:15

Vale la pena mencionar que el hermano de' exec también existe llamado execfile si desea llamar a un archivo python. Eso a veces es bueno si está trabajando en un paquete de terceros que tienen IDES terribles incluidos y desea codificar fuera de su paquete.

Ejemplo:

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

O:

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

 0
Author: user1767754,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-02 00:42:18