Para ser justos, a diferencia de la otra pregunta, esta no es un duplicado. Y otros han publicado preguntas mucho más básicas que esto.
DNS
8
La respuesta correcta, por supuesto, es casi siempre "¡no!".
bobince
23
@S. Lott: ¿No has leído las preguntas frecuentes recientemente? "También está perfectamente bien hacer y responder su propia pregunta de programación, pero finja que está en peligro: formúlelo en forma de pregunta". Esta no es una mala pregunta. +1
Devin Jeanpierre
49
@ S.Lott: No lo haces. No necesitas hacerlo. Si la pregunta ya no está en el sitio, entonces es un juego justo (de acuerdo con las preguntas frecuentes, como ya se señaló). Simplemente responda cada pregunta como si el OP necesitara ayuda. Puede que no, pero el próximo tipo que lea su pregunta probablemente lo hará. Solo mis 2 centavos.
Bill the Lizard
1
A todos ustedes diciendo que no lo hagan: tengo un caso en el que absolutamente lo necesito. Implica procesamiento distribuido.
>>> mycode ='print "hello world"'>>>exec(mycode)Hello world
Cuando necesite el valor de una expresión, use eval(string):
>>> x = eval("2+2")>>> x4
Sin embargo, el primer paso debería ser preguntarse si realmente lo necesita. El código de ejecución generalmente debe ser el último recurso: es lento, feo y peligroso si puede contener código ingresado por el usuario. Siempre debe buscar alternativas primero, como funciones de orden superior, para ver si pueden satisfacer mejor sus necesidades.
pero ¿qué hay del alcance del código ejecutado por 'exec'? ¿Está anidado?
jondinham
21
Un caso común en el que alguien quiere usar 'exec' es algo así if s=='foo': x.foo = 42 elif s=='bar': x.bar = 42, etc., que luego pueden escribir como exec ("x.%s = 42" % s). Para este caso común (donde solo necesita acceder al atributo de un objeto que está almacenado en una cadena), existe una función mucho más rápida, más limpia y más segura getattr: simplemente escriba getattr(x, s) = 42para decir lo mismo.
ShreevatsaR
55
¿Cómo es exec más lento que el intérprete de Python?
Cris Stringfellow
66
@ShreevatsaR no quieres decir setattr(x, s, 42)? Lo intenté getattr(x, 2) = 42y falló concan't assign to function call: <string>, line 1
Tanner Semerad
66
@ Tanner: Hmm. Sí, de hecho, setattr(x, s, 42)es la sintaxis correcta. Sorprendido, tardó tanto tiempo en detectar ese error. De todos modos, el punto es eso getattry setattrson una alternativa a execcuando todo lo que quieres es obtener un miembro arbitrario, buscado por cadena.
ShreevatsaR
68
En el ejemplo, una cadena se ejecuta como código utilizando la función exec.
import sysimportStringIO# 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 = codeErrexec 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()
intercambiar stdout y stderr así me pone muy nervioso. Esto parece que podría causar grandes problemas de seguridad. ¿Hay alguna manera de evitar eso?
Narcolapser
1
@Narcolapser debería estar más preocupado por el uso de mych exec(a menos que sepa que la cadena de código proviene de una fuente confiable).
bruno desthuilliers
27
evaly execson la solución correcta, y pueden usarse de una manera más segura .
Como se discutió en el manual de referencia de Python y se explicó claramente en este tutorial, las funciones evaly exectoman 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 =2def 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'isnot 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'isnot defined
En esencia, está definiendo el espacio de nombres en el que se ejecutará el código.
No es posible hacer que eval sea seguro: Eval realmente es peligroso . Si me quitas el código y lo evalúas, puedo desconectar tu programa Python. Juego terminado.
Ned Batchelder
3
@ v.oddou Estaba respondiendo a la declaración de alan, "eval y exec .. pueden usarse de manera segura". Esto es falso Si alguien dijera "bash se puede usar de manera segura", eso también sería falso. Bash es peligroso. Es un peligro necesario, pero peligroso a pesar de todo. Afirmar que eval puede hacerse seguro es simplemente incorrecto.
Ned Batchelder
1
@NedBatchelder sí, de hecho. y el enlace al que apunta es buen material. con el poder viene la responsabilidad, por lo que el punto es simplemente ser consciente del poder potencial de eval. y si decidimos que poder = peligro.
v.oddou
3
@NedBatchelder Muchas piezas de código escritas en Python también pueden ser peligrosas, pero ¿por qué asume eso evalo execestá destinado a ser utilizado exec(input("Type what you want"))? Hay muchos casos en los que un programa puede escribir un procedimiento o una función como resultado de un cálculo; Las funciones resultantes serán tan seguras y rápidas (una vez evaluadas) como cualquier otra parte de un programa bueno y bien escrito. Un programa inseguro que contiene execno es más peligroso que un programa inseguro que hace el daño por sí mismo, ya que execno le da ningún nuevo privilegio al programa.
Thomas Baruchel el
1
@ThomasBaruchel nuevamente, mi punto es contrarrestar la noción de que eval o exec pueden ser seguros. En particular, esta respuesta afirma que controlar a los globales y locales hará posible usarlos de manera segura. Eso es falso. Cada vez que use exec y eval, debe saber con precisión qué código se está ejecutando. Si no lo hace, entonces está abierto a operaciones peligrosas.
Ned Batchelder
21
¡Recuerde que a partir de la versión 3 execes una función!
así que siempre use en exec(mystring)lugar de exec mystring.
eval()es solo para expresiones, aunque eval('x+1')funciona, eval('x=1')no funcionará, por ejemplo. En ese caso, es mejor usarlo exec, o incluso mejor: intente encontrar una mejor solución :)
Cuando necesite el valor de una expresión, use eval.
Sin embargo, el primer paso debería ser preguntarse si realmente lo necesita. El código de ejecución generalmente debe ser el último recurso : es lento, feo y peligroso si puede contener código ingresado por el usuario. Siempre debe buscar alternativas primero, como funciones de orden superior , para ver si pueden satisfacer mejor sus necesidades.
No intentes eludir las expresiones idiomáticas de Python porque algún otro idioma lo hace de manera diferente. Los espacios de nombres están en Python por una razón y solo porque le brinde la herramienta execno significa que deba usar esa herramienta.
¡Eva no es seguro, incluso si elimina 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 elemento de la lista, puedes atacar el sistema .
Entonces, ¿se puede evaluar la seguridad? Difícil de decir. En este punto, mi mejor conjetura es que no puede hacer ningún daño si no puede usar guiones bajos dobles, por lo que tal vez si excluye cualquier cadena con guiones bajos dobles está a salvo. Tal vez...
Primero, exechace que sea más difícil para los seres humanos leer su código . Para averiguar qué está sucediendo, no solo tengo que leer su código, tengo que leer su código, averiguar qué cadena va a generar y luego leer ese código virtual. Entonces, si está trabajando en un equipo, o está publicando software de código abierto, o solicita ayuda en algún lugar como StackOverflow, está haciendo que sea más difícil para otras personas ayudarlo. Y si hay alguna posibilidad de que vaya a depurar o expandir este código dentro de 6 meses, lo está dificultando directamente.
"Mi mejor conjetura es que no puede hacer ningún daño si no puede usar guiones bajos dobles": puede construir una cadena que contenga guiones bajos dobles y luego llamar a evaluar esa cadena.
Stanley Bak
Un buen consejo, a menos que esté escribiendo un generador de código, un corredor de trabajos o similar ... lo que la mayoría de las personas aquí probablemente están haciendo.
Erik Aronesty
Tengo que importar una ruta relativa desde un archivo de configuración ( cfg.yaml): reldir : ../my/dir/ y reldir = cfg[reldir]. Sin embargo, como este código de Python se ejecutará tanto en Windows como en Linux, necesito que esto se ajuste a los diferentes divisores de ruta de los sistemas operativos; ya sea \\ o /. Entonces lo uso reldir : os.path.join('..','my','dir')en el archivo de configuración. Pero esto solo resulta reldirser esta cadena literal, no se evalúa, por lo que no puedo abrir un archivo reldir. ¿Tienes una sugerencia?
Marie P.
9
Logra ejecutar código usando exec, como con la siguiente sesión IDLE:
Esto no funciona en python normal. Al menos no en Python 3.
Thomas Ahle
6
Como los otros mencionaron, es "ejecutivo".
pero, en caso de que su código contenga variables, puede usar "global" para acceder a él, también para evitar que el compilador genere el siguiente error:
NameError: el nombre 'p_variable' no está definido
Vale la pena mencionar que ese exechermano existe también llamado execfilesi desea llamar a un archivo python. Eso a veces es bueno si está trabajando en un paquete de terceros que tiene IDE terribles incluidos y desea codificar fuera de su paquete.
La solución más lógica sería utilizar la función incorporada eval () . Otra solución es escribir esa cadena en un archivo temporal de Python y ejecutarla.
Ok .. Sé que esto no es exactamente una respuesta, pero posiblemente una nota para la gente que mira esto como yo. Quería ejecutar código específico para diferentes usuarios / clientes pero también quería evitar el 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 aplicó ningún filtro para ese cliente, simplemente continuó
import imp
def get_customer_module(customerName='default', name='filter'):
lm =Nonetry:
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 isnotNone:
m.apply_address_filter(myobj)
para que customerName = "jj" ejecute apply_address_filter desde el archivo customer_filters \ jj_filter.py
Respuestas:
Para las declaraciones, use
exec(string)
(Python 2/3) oexec string
(Python 2):Cuando necesite el valor de una expresión, use
eval(string)
:Sin embargo, el primer paso debería ser preguntarse si realmente lo necesita. El código de ejecución generalmente debe ser el último recurso: es lento, feo y peligroso si puede contener código ingresado por el usuario. Siempre debe buscar alternativas primero, como funciones de orden superior, para ver si pueden satisfacer mejor sus necesidades.
fuente
if s=='foo': x.foo = 42 elif s=='bar': x.bar = 42
, etc., que luego pueden escribir comoexec ("x.%s = 42" % s)
. Para este caso común (donde solo necesita acceder al atributo de un objeto que está almacenado en una cadena), existe una función mucho más rápida, más limpia y más seguragetattr
: simplemente escribagetattr(x, s) = 42
para decir lo mismo.setattr(x, s, 42)
? Lo intentégetattr(x, 2) = 42
y falló concan't assign to function call: <string>, line 1
setattr(x, s, 42)
es la sintaxis correcta. Sorprendido, tardó tanto tiempo en detectar ese error. De todos modos, el punto es esogetattr
ysetattr
son una alternativa aexec
cuando todo lo que quieres es obtener un miembro arbitrario, buscado por cadena.En el ejemplo, una cadena se ejecuta como código utilizando la función exec.
fuente
exec
(a menos que sepa que la cadena de código proviene de una fuente confiable).eval
yexec
son la solución correcta, y pueden usarse de una manera más segura .Como se discutió en el manual de referencia de Python y se explicó claramente en este tutorial, las funciones
eval
yexec
toman dos parámetros adicionales que permiten al usuario especificar qué funciones y variables globales y locales están disponibles.Por ejemplo:
En esencia, está definiendo el espacio de nombres en el que se ejecutará el código.
fuente
eval
oexec
está destinado a ser utilizadoexec(input("Type what you want"))
? Hay muchos casos en los que un programa puede escribir un procedimiento o una función como resultado de un cálculo; Las funciones resultantes serán tan seguras y rápidas (una vez evaluadas) como cualquier otra parte de un programa bueno y bien escrito. Un programa inseguro que contieneexec
no es más peligroso que un programa inseguro que hace el daño por sí mismo, ya queexec
no le da ningún nuevo privilegio al programa.¡Recuerde que a partir de la versión 3
exec
es una función!así que siempre use en
exec(mystring)
lugar deexec mystring
.fuente
eval()
es solo para expresiones, aunqueeval('x+1')
funciona,eval('x=1')
no funcionará, por ejemplo. En ese caso, es mejor usarloexec
, o incluso mejor: intente encontrar una mejor solución :)fuente
Evitar
exec
yeval
Usar
exec
yeval
en Python está muy mal visto.Hay mejores alternativas
De la respuesta superior (énfasis mío):
¿De alternativas a exec / eval?
No es idiomático
De http://lucumr.pocoo.org/2011/2/1/exec-in-python/ (el énfasis es mío)
Es peligroso
De http://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html (énfasis mío)
Es dificil de leer y entender
De http://stupidpythonideas.blogspot.it/2013/05/why-evalexec-is-bad.html (énfasis mío):
fuente
cfg.yaml
):reldir : ../my/dir/
yreldir = cfg[reldir]
. Sin embargo, como este código de Python se ejecutará tanto en Windows como en Linux, necesito que esto se ajuste a los diferentes divisores de ruta de los sistemas operativos; ya sea\\
o/
. Entonces lo usoreldir : os.path.join('..','my','dir')
en el archivo de configuración. Pero esto solo resultareldir
ser esta cadena literal, no se evalúa, por lo que no puedo abrir un archivoreldir
. ¿Tienes una sugerencia?Logra ejecutar código usando exec, como con la siguiente sesión IDLE:
fuente
Como los otros mencionaron, es "ejecutivo".
pero, en caso de que su código contenga variables, puede usar "global" para acceder a él, también para evitar que el compilador genere el siguiente error:
fuente
Usa eval .
fuente
Vale la pena mencionar que ese
exec
hermano existe también llamadoexecfile
si desea llamar a un archivo python. Eso a veces es bueno si está trabajando en un paquete de terceros que tiene IDE terribles incluidos y desea codificar fuera de su paquete.Ejemplo:
execfile('/path/to/source.py)'
o:
exec(open("/path/to/source.py").read())
fuente
Echa un vistazo a eval :
fuente
Intenté algunas cosas, pero lo único que funcionó fue lo siguiente:
salida:
10
fuente
La solución más lógica sería utilizar la función incorporada eval () . Otra solución es escribir esa cadena en un archivo temporal de Python y ejecutarla.
fuente
Ok .. Sé que esto no es exactamente una respuesta, pero posiblemente una nota para la gente que mira esto como yo. Quería ejecutar código específico para diferentes usuarios / clientes pero también quería evitar el 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 aplicó ningún filtro para ese cliente, simplemente continuó
para que customerName = "jj" ejecute apply_address_filter desde el archivo customer_filters \ jj_filter.py
fuente