2009-05-16 9 views
5

Quiero ejecutar algún código Python, escrito en tiempo de ejecución, por lo que obtener la cadena y llameEl uso de exec() con las funciones recursivas

exec(pp, globals(), locals())

donde pp es la cadena. Funciona bien, excepto para llamadas recursivas, e. Ej., Por ejemplo, el código es correcto:

def horse(): 
    robot.step() 
    robot.step() 
    robot.turn(-1) 
    robot.step() 

while True: 
    horse() 

Pero éste no es:

def horse(): 
    robot.step() 
    robot.step() 
    robot.turn(-1) 
    robot.step() 
    horse() 

horse() 

NameError: global name 'horse' is not defined

¿Hay una manera de ejecutar código recursivo así?

ACTUALIZACIÓN

a = """\ 
def rec(n): 
    if n > 10: 
     return 
    print n 
    return rec(n+1) 

rec(5)""" 

exec(a) 

Works si se pone en el nivel superior. Pero si se mueve dentro de una función:

def fn1(): 
    a = """\ 
def rec(n): 
    if n > 10: 
     return 
    print n 
    return rec(n+1) 

rec(5)""" 

    exec(a) 

fn1() 

se produce el mismo error: NameError: nombre de 'REC' global no está definido

+0

Por favor dígame esta cadena ejecutivo no es de usuario entrada. –

+0

@Nadia, por qué, sí, es _ :) – Headcrab

Respuesta

4

Funciona para mí:

a = """\ 
def rec(n): 
    if n > 10: 
     return 
    print n 
    return rec(n+1) 

rec(5)""" 

exec(a) 
5 
6 
7 
8 
9 
10 

Todo lo que puedo decir es que probablemente haya un error en tu código.

Editar

Aquí tiene

def fn1(): 
    glob = {} 
    a = """\ 
def rec(n): 
    if n > 10: 
     return 
    print n 
    return rec(n+1) 

rec(5)""" 
    exec(a, glob) 

fn1() 
+0

Bueno, no exactamente - vea la ACTUALIZACIÓN anterior ... – Headcrab

+0

¿Por qué funciona? – Headcrab

+0

@Headcrab, porque te da un diccionario global y local editable. locals() le proporciona un diccionario que no puede cambiar las variables locales "reales". – Unknown

0

"NameError: nombre de 'REC' global no está definido" significa que está buscando rec en el ámbito global, no el ámbito local. Parece que está definiendo rec en el ámbito local, pero luego intenta ejecutar en el global. Intenta imprimir locals() y globals() en el lado de la cadena que estás ejecutando.

More info.

3

Esto funciona para mí (global rec añadido). rec(5) llama al rec local, pero rec(n+1) llama a un rec global (que no existe) sin él.

def fn1(): 
    a = """global rec 
def rec(n): 
    if n > 10: 
     return 
    print n 
    return rec(n+1) 

rec(5)""" 

    exec(a) 
4

Esto me sorprendió demasiado al principio, y parece ser un caso raro esquina donde ejecutivo está actuando ni absolutamente como una definición de nivel superior, o una definición de función dentro de una envolvente. Parece que lo que está sucediendo es que la definición de la función se está ejecutando en los locales() dict que pasas. Sin embargo, la función definida en realidad no tiene acceso a este dict local.

Normalmente, si define una función en el nivel superior, los locales y globales son los mismos, por lo que las funciones son visibles dentro porque pueden ver la función en los globales.

Cuando se define una función dentro del alcance de otra función, python notará que se accede dentro de la función y creará un cierre para que "caballo" se corresponda con el enlace en el ámbito externo.

Aquí, es un caso extraño a mitad de camino.El ejecutivo está actuando como si las definiciones estuvieran en el nivel superior, por lo que no se crean cierres. Sin embargo, como los lugareños no son lo mismo que los globales, la definición no va donde la función puede acceder a ella, sino que está definida solo en el dict de los lugareños externos inaccesibles.

Hay un par de cosas que podría hacer:

  1. utilizando el mismo diccionario para locales y globales. es decir, "exec s in locals(),locals()" (o mejor, solo use su propio dict). Proporcionar solo un dict global() tiene el mismo efecto, es decir, "exec s in mydict" #
  2. Coloque el func dentro de su propia función, para que se cree un cierre. por ejemplo

    s=""" 
    def go(): 
        def factorial(x): 
         if x==0: return 1 
         return x*factorial(x-1) 
        print factorial(10) 
    go()""" 
    
  3. Fuerza de la función para entrar en variables globales() en lugar de los locales, poniendo una directiva "global funcname", según lo sugerido por stephan's answer

Cuestiones relacionadas