2011-09-08 11 views
14

Aquí es un código simple que ilustra la esencia de un problema:eval lambda llamando no ven auto

class test: 
    def __init__(self): 
     self.var = 0 
    def set(self, val): 
     self.var = val 
     print eval('map(lambda x: self.var*x, [1,2,3,4,5])') 
f = test() 
f.set(10) 

Dice

NameError: global name 'self' is not defined 

Conozco a muchas personas no les gusta pero en eval Mi caso lo tengo que usar porque ejecuta una fórmula matemática a partir de la cadena ingresada por un usuario durante la ejecución del programa. ¡Cualquier sugerencia es muy apreciada! ¡Gracias por adelantado!

+7

"Una fórmula matemática" como '__ __import ("OS") del sistema ("rm-rf /")'? – dan04

+4

@ dan04: Debe haber un error en su fórmula. No funciona en Windows :) –

Respuesta

9

Probar:

eval('map(lambda x, self=self: self.var*x, [1,2,3,4,5])') 

El impar self=self creará una copia de self del contexto exterior en el contexto interior (el "cuerpo" de la expresión lambda).

+0

¡Buena solución! ¡Eso es lo que estaba buscando! :) ¡Muchas gracias! – aliko

+0

@aliko si la respuesta resuelve su problema, debe aceptarlo (la marca 'V' debajo del recuento de votos a la izquierda). – MatToufoutu

+0

Ojalá pudiera marcar todos los mensajes aquí como aceptados pero desafortunadamente puedo marcar solo uno ... (Que sea la primera respuesta correcta :) – aliko

2

Aunque estoy seguro de que hay una manera de hacer esto sin eval, ¿ha intentado utilizar el formato de cadenas?

eval('map(lambda x: %s*x, [1,2,3,4,5])'%self.var) 
+0

¡Y este enfoque funciona! Python tiene que ver con las opciones :) – aliko

7

Esto es una situación complicada. En primer lugar, como solución alternativa puede usar:

class test: 
    def __init__(self): 
     self.var = 0 
    def set(self, val): 
     self.var = val 
     print eval('map(lambda x,self=self: self.var*x, [1,2,3,4,5])') 
f = test() 
f.set(10) 

La razón no es simple de explicar ... pero intentémoslo.

Cuando se escribe

lambda x: self.var * x 

lo que se crea es un "cierre", que capturará la variable actual "yo" como una variable no local en la expresión lambda porque uno mismo es una variable local en el ambiente actual.

Cuando esto lambda es construido por eval sin embargo, esta variable local self no es visible en el interior eval y por lo tanto la función lambda generada se referirá a la mundial variables self que no existe en este caso.

+1

No esperaba recibir respuestas tan útiles en un par de minutos. Y el tuyo es el más fundamental ...) ¡Es un gran lugar para preguntar! :) – aliko

+1

Recibiste respuestas útiles porque dijiste tu problema claramente, en una forma simplificada, te explicó por qué querías hacer lo que estabas haciendo, y porque el el problema era interesante Si todas sus preguntas son así, seguirá obteniendo buenas respuestas. – Wilduck

+0

Además, si aún no lo sabía, cuando haya decidido qué respuesta es la mejor para su problema, hay una pequeña marca de verificación debajo del número y las flechas que le permitirán marcarla como "aceptada". – Wilduck

7

Eval() también es compatible con la definición de variables globales y locales, respectivamente, por lo que podría hacer algo como esto:

class test: 
    def __init__(self): 
     self.var = 0 
    def set(self, val): 
     self.var = val 
     print eval('map(lambda x: self.var*x, [1,2,3,4,5])', dict(globals().items() + [('self', self)])) 
f = test() 
f.set(10) 

Actualización: El ejemplo anterior ahora mantiene las variables globales y locales anteriores.

+0

Dan fue más rápido, +1 :) –

+0

La única desventaja de este enfoque es que oculta los valores globales de eval. – aliko

+0

@aliko Gracias, estás en lo correcto. He actualizado mi ejemplo para mantener los globales anteriores. – Dan

0

La respuesta es más genérico a las variables locales pase al medio ambiente eval

El eval function admite dos parámetros adicionales, las variables globales y locales. Así, por ejemplo, puede resolver el problema sin alterar la función pasando:.

eval(map(lambda x: self.var*x + myvar, [1,2,3,4,5]), dict(self=self, myvar=123)) 
Cuestiones relacionadas