Pregunta

Estoy escribiendo un motor de juego usando pygame y box2d, y en el generador de personajes, quiero poder escribir el código que se ejecutará en eventos keydown.

Mi plan era tener un editor de texto en el generador de caracteres que le permitiera escribir código similar a:

if key == K_a:
    ## Move left
    pass
elif key == K_d:
    ## Move right
    pass

Recuperaré el contenido del editor de texto como una cadena, y quiero que el código se ejecute en un método en este método de Carácter:

def keydown(self, key):
    ## Run code from text editor

¿Cuál es la mejor manera de hacer eso?

¿Fue útil?

Solución

Puede usar el eval (string) método para hacer esto.

Definición

eval (code, globals = None, locals = None)
El código es solo el código Python estándar, esto significa que todavía necesita una sangría adecuada.

Los globales pueden tener un __builtins__ personalizado, que podría ser útil por motivos de seguridad.

Ejemplo

eval("print('Hello')")

Imprimiría hello en la consola. También puede especificar variables locales y globales para que el código las use:

eval("print('Hello, %s'%name)", {}, {'name':'person-b'})

Preocupaciones de seguridad

Ten cuidado, sin embargo. Cualquier entrada del usuario será ejecutada. Considere:

eval("import os;os.system('sudo rm -rf /')")

Hay varias formas de evitarlo. Lo más fácil es hacer algo como:

eval("import os;...", {'os':None})

Lo que arrojará una excepción, en lugar de borrar su disco duro. Si bien su programa es de escritorio, esto podría ser un problema si la gente redistribuye los scripts, lo que imagino que está destinado.

Ejemplo extraño

Aquí hay un ejemplo del uso de eval bastante extraño:

def hello() : print('Hello')
def world() : print('world')
CURRENT_MOOD = 'happy'

eval(get_code(), {'contrivedExample':__main__}, {'hi':hello}.update(locals()))

Lo que esto hace en la línea de evaluación es:

  1. Le da al módulo actual otro nombre (se convierte en ideadoEjemplo para el script). El consumidor puede llamar a contrivedExample.hello () ahora.)
  2. Define hi como apuntando a hello
  3. Combinó ese diccionario con la lista de globales actuales en el módulo en ejecución.

FAIL

Resulta (¡gracias a los comentaristas!) que realmente necesitas usar la declaración exec . Oops grandes Los ejemplos revisados ??son los siguientes:


exec Definición

(¡Esto parece familiar!) Exec es una declaración:
exec " código " [en alcance] Donde alcance es un diccionario de variables locales y globales. Si esto no se especifica, se ejecuta en el alcance actual.

El código es solo el código estándar de Python; esto significa que aún necesita una sangría adecuada.

exec Ejemplo

exec "print('hello')"

Imprimiría hello en la consola. También puede especificar variables locales y globales para que el código las use:

eval "print('hello, '+name)" in {'name':'person-b'}

exec Preocupaciones de seguridad

Ten cuidado, sin embargo. Cualquier entrada del usuario será ejecutada. Considere:

exec "import os;os.system('sudo rm -rf /')"

Imprimir declaración

Como también señalaron los comentaristas, print es una declaración en todas las versiones de Python anteriores a la 3.0. En 2.6, el comportamiento se puede cambiar escribiendo desde __future__ import print_statement . De lo contrario, use:

print "hello"

En lugar de:

print("hello")

Otros consejos

Como otros han señalado, puede cargar el texto en una cadena y usar exec " codestring " . Si ya está contenido en un archivo, usar execfile evitará tener que cargarlo.

Una nota de rendimiento: debe evitar ejecutar el código varias veces, ya que analizar y compilar la fuente de Python es un proceso lento. es decir. no tiene:

def keydown(self, key):
    exec user_code

Puedes mejorar esto un poco compilando la fuente en un objeto de código (con compile () y ejecutando eso, o mejor, construyendo una función que mantengas alrededor, y solo compila una vez. Solicite al usuario que escriba " def my_handler (args ...) " ;, o lo anteponga usted mismo y haga algo como:

user_source = "def user_func(args):\n" + '\n'.join("    "+line for line in user_source.splitlines())

d={}
exec user_source in d
user_func = d['user_func']

Luego más tarde:

if key == K_a:
   user_func(args)

Puede usar eval ()

eval o exec. Definitivamente deberías leer la referencia de la biblioteca de Python antes de programar.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top