¿Cómo ejecuto una cadena que contiene código de Python en Python?

11 minutos de lectura

¿Como ejecuto una cadena que contiene codigo de Python en
hekevintran

¿Cómo ejecuto una cadena que contiene código de Python en Python?

  • 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 esta.

    – DNS

    31 de marzo de 2009 a las 16:25

  • La respuesta correcta, por supuesto, es casi siempre “¡no!”.

    – bobince

    31 de marzo de 2009 a las 16:28

  • @S. Lott: ¿No has leído las preguntas frecuentes recientemente? “También está perfectamente bien hacer y responder tu propia pregunta de programación, pero finge que estás en Jeopardy: exprésalo en forma de pregunta”. Esta no es una mala pregunta. +1

    – Devin Jean Pierre

    31 de marzo de 2009 a las 17:48

  • @ S. Lott: No lo haces. No es necesario. Si la pregunta aún no está en el sitio, entonces es un juego justo (según las preguntas frecuentes, como ya se señaló). Simplemente responda todas las preguntas como si el OP necesitara ayuda. Puede que no, pero el próximo tipo que lea su pregunta probablemente lo hará. Sólo mis 2 centavos.

    – Bill el lagarto

    2 de abril de 2009 a las 18:13

  • A todos los que dicen que no lo hagan: tengo un caso en el que absolutamente necesito hacerlo. Se trata de procesamiento distribuido.

    – sudo

    1 de agosto de 2016 a las 8:23

1646962991 746 ¿Como ejecuto una cadena que contiene codigo de Python en
Brian

Para declaraciones, utilice exec(string) (Python 2/3) o exec string (Pitón 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 es necesario. Por lo general, ejecutar código debería ser la posición de ú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 ‘ejec’? esta anidado?

    – jondinham

    6 de marzo de 2012 a las 10:24

  • Un caso común en el que alguien quiere usar ‘ejec’ es algo como 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, limpia y segura getattr: solo escribe getattr(x, s) = 42 para significar lo mismo.

    – ShreevatsaR

    19 de abril de 2012 a las 19:18


  • ¿Cómo es exec más lento que el intérprete de python?

    – Cris Stringfellow

    6 de febrero de 2013 a las 16:36

  • @ShreevatsaR no querrás decir setattr(x, s, 42)? Lo intenté getattr(x, 2) = 42 y fracasó con can't assign to function call: <string>, line 1

    – Tanner Semerad

    11/10/2013 a las 17:44

  • @Tanner: Mmmm. si de hecho setattr(x, s, 42) es la sintaxis correcta. Me sorprende que haya tardado tanto en detectarse ese error. De todos modos, el punto es que getattr y setattr son una alternativa a exec cuando todo lo que quiere es obtener un miembro arbitrario, buscado por cadena.

    – ShreevatsaR

    11/10/2013 a las 19:01

En el ejemplo, una cadena se ejecuta como código utilizando 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()

  • cambiar stdout y stderr así me pone muy nervioso. esto parece que podría causar grandes problemas de seguridad. ¿Hay alguna manera de evitar eso?

    – Narcolapsor

    23 de mayo de 2011 a las 13:33

  • @Narcolapser deberías estar más preocupado por usar exec en absoluto (a menos que usted saber la cadena de código proviene de una fuente confiable).

    – bruno destuilliers

    2 dic 2019 a las 17:00

1646962991 781 ¿Como ejecuto una cadena que contiene codigo de Python en
alan

eval y exec son la solución correcta, y se pueden utilizar en un más seguro conducta.

Como se discutió en manual de referencia de python y claramente explicado en esta tutorial, el eval y exec Las funciones 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.

  • No es posible hacer eval seguro: Eval es realmente peligroso. Si toma el código de mí y lo evalúa, puedo fallar su programa de Python. Juego terminado.

    –Ned Batchelder

    18 de febrero de 2013 a las 4:20

  • @v.oddou Estaba respondiendo a la declaración de alan, “eval y exec … se pueden usar 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 al fin y al cabo. Afirmar que eval se puede hacer seguro es simplemente incorrecto.

    –Ned Batchelder

    13 de enero de 2015 a las 15:10

  • @NedBatchelder sí, de hecho. y el enlace al que apuntas es un 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

    14 de enero de 2015 a las 2:08

  • @NedBatchelder Muchas piezas de código escritas en Python también pueden ser peligrosas, pero ¿por qué supones eso? eval o exec están destinados a ser utilizados como 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 exec no es más peligroso que un programa inseguro haciendo el daño por sí mismo como exec no otorga ningún privilegio nuevo al programa.

    – Tomás Baruchel

    16 de noviembre de 2016 a las 10:46


  • @ThomasBaruchel nuevamente, mi punto es contrarrestar la noción de que eval o exec pueden ser seguros. En particular, esta respuesta afirma que controlar los globales y los locales hará posible usarlos de manera segura. Eso es falso. Cada vez que usa exec y eval, debe saber con precisión qué código se está ejecutando. Si no lo hace, entonces está expuesto a operaciones peligrosas.

    –Ned Batchelder

    16 de noviembre de 2016 a las 23:10

1646962992 608 ¿Como ejecuto una cadena que contiene codigo de Python en
hermanos

Recuerda que a partir de la versión 3 exec es una función!
así que siempre usa exec(mystring) en lugar de exec mystring.

1646962992 317 ¿Como ejecuto una cadena que contiene codigo de Python en
Caridorc

Evitar exec y eval

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

hay mejores alternativas

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

Para declaraciones, utilice exec.

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

Sin embargo, el primer paso debe ser preguntarse si realmente es necesario. Ejecutar código generalmente debe ser la posición de último recurso: Es lento, feo y peligroso si puede contener código ingresado por el usuario. Siempre debes mirar alternativas primero, como funciones de orden superiorpara ver si estos pueden satisfacer mejor sus necesidades.

¿De Alternativas a exec/eval?

establecer y obtener valores de variables con los nombres en cadenas

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

En su lugar, mejor usa un dict.

no es idiomatico

Desde http://lucumr.pocoo.org/2011/2/1/exec-in-python/ (énfasis mío)

Python no es PHP

No intente eludir los modismos 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 te da la herramienta exec no significa que debas usar esa herramienta.

Es peligroso

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

¡Entonces eval no es seguro, incluso si elimina todos los elementos globales y los elementos integrados!

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 fuera de la lista, puede atacar el sistema.

Entonces, ¿se puede hacer eval de forma segura? Difícil de decir. En este punto, mi mejor suposición 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é seguro. Quizás…

Es difícil de leer y entender.

Desde http://stupidpythonideas.blogspot.it/2013/05/por-que-evalexec-es-malo.html (énfasis mío):

Primero, exec hace que sea más difícil para los seres humanos leer su código. Para averiguar qué está pasando, 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. Por lo tanto, si está trabajando en un equipo, publicando software de código abierto o pidiendo ayuda en algún lugar como StackOverflow, está dificultando que otras personas lo ayuden. Y si hay alguna posibilidad de que vaya a depurar o expandir este código dentro de 6 meses, lo está haciendo más difícil para usted directamente.

  • “Mi mejor suposición es que no puede hacer ningún daño si no puede usar guiones bajos dobles”: podría construir una cadena que contenga guiones bajos dobles y luego llamar a eval esa cadena.

    -Stanley Bak

    11/10/2016 a las 16:11

  • buen consejo, a menos que esté escribiendo un generador de código, o un ejecutor de trabajos o algo similar… que la mayoría de la gente aquí probablemente esté haciendo.

    – Erik Aronesty

    3 mayo 2019 a las 12:59


  • 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 python se ejecutará tanto en Windows como en Linux, necesito que se ajuste a los diferentes divisores de ruta de los sistemas operativos; cualquiera \\ o /. entonces uso reldir : os.path.join('..','my','dir') en el archivo de configuración. Pero esto sólo resulta en reldir siendo esta cadena literal, no siendo evaluada, por lo que no puedo abrir un archivo en reldir. ¿Tienes una sugerencia?

    – María. pags.

    11 de marzo de 2020 a las 14:18


  • Uhm, no. Estos son altamente pitónicos. ¿Qué crees que es un REPL?

    – Resplandor

    17 oct 2020 a las 20:30

¿Como ejecuto una cadena que contiene codigo de Python en
Jérôme Verstrynge

eval() es solo para expresiones, mientras que eval('x+1') obras, eval('x=1') no funcionará por ejemplo. En ese caso, es mejor usar execo incluso mejor: intenta encontrar una mejor solución 🙂

  • “Mi mejor suposición es que no puede hacer ningún daño si no puede usar guiones bajos dobles”: podría construir una cadena que contenga guiones bajos dobles y luego llamar a eval esa cadena.

    -Stanley Bak

    11/10/2016 a las 16:11

  • buen consejo, a menos que esté escribiendo un generador de código, o un ejecutor de trabajos o algo similar… que la mayoría de la gente aquí probablemente esté haciendo.

    – Erik Aronesty

    3 mayo 2019 a las 12:59


  • 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 python se ejecutará tanto en Windows como en Linux, necesito que se ajuste a los diferentes divisores de ruta de los sistemas operativos; cualquiera \\ o /. entonces uso reldir : os.path.join('..','my','dir') en el archivo de configuración. Pero esto sólo resulta en reldir siendo esta cadena literal, no siendo evaluada, por lo que no puedo abrir un archivo en reldir. ¿Tienes una sugerencia?

    – María. pags.

    11 de marzo de 2020 a las 14:18


  • Uhm, no. Estos son altamente pitónicos. ¿Qué crees que es un REPL?

    – Resplandor

    17 oct 2020 a las 20:30

1646962993 908 ¿Como ejecuto una cadena que contiene codigo de Python en
pulpograbbus

Usted logra ejecutar el código usando exec, como con la siguiente sesión INACTIVA:

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

4

  • Esto no funciona en Python normal. Al menos no en Python 3.

    – Tomas Ahle

    20 de agosto de 2018 a las 11:22

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad