2016-12-19 2 views
7

Pourquoi le eval de Python ne fonctionne pas dans une fonction? Le même code fonctionne dans un environnement global, mais ne fonctionne pas dans la fonction foo.Python eval ne fonctionne pas dans une fonction

Exemple simple:

fn = '/tmp/tmp' 
mode = 'single' 

def foo(cmd, fn, mode): 
    eval(compile(cmd, fn, mode)) # <<< this does not work 
    print 'foo: cmd=', cmd 
    print 'foo: x=', x 

cmd = "x = 1" 
eval(compile(cmd, fn, mode)) # <<< this works 
print 'global scope: cmd=', cmd 
print 'global scope: x=', x 

del(x) 
foo('x = 9', fn, mode) 

Ceci est la sortie et le message d'erreur:

global scope: cmd= x = 1 
global scope: x= 1 
foo: cmd= x = 9 
foo: x= 
Traceback (most recent call last): 
    File "ctest.py", line 20, in <module> 
    foo('x = 9', fn, mode) 
    File "ctest.py", line 12, in foo 
    print 'foo: x=', x 
NameError: global name 'x' is not defined 
+0

êtes-vous sûr que vous ne souhaitez pas affecter sa valeur à quelque chose? –

+0

Juste essayé ceci: 'x' finit dans la dict' locals', tout comme avec exec, mais alors que 'exec (cmd)' fonctionne dans la fonction, 'eval (compile (...))' ne fait pas. –

+0

Aussi, si vous mettez 'eval (" x ")' au lieu de 'x' dans' print 'foo: x =', x' cela fonctionne aussi. Même comportement dans les deux, Python 2.7 et Python 3.4 –

Répondre

4

Dans votre fonction, l'exécution ne fonctionne pas mais x finit dans locals(), puis les essais de déclaration print pour trouver x dans globals() et soulève ainsi le NameError.

fn = '/tmp/tmp' 
mode = 'single' 

def foo(cmd, fn, mode): 
    eval(compile(cmd, fn, mode)) 
    print 'locals:', locals() 
    print 'foo: cmd=', cmd 
    print 'foo: x=', locals()['x'] 

cmd = "x = 1" 
eval(compile(cmd, fn, mode)) 
print 'global scope: cmd=', cmd 
print 'global scope: x=', x 

del(x) 
foo('x = 9', fn, mode) 

Sorties:

global scope: cmd= x = 1 
global scope: x= 1 
locals: {'x': 9, 'cmd': 'x = 9', 'mode': 'single', 'fn': '/tmp/tmp'} 
foo: cmd= x = 9 
foo: x= 9 
+1

Juste remarqué qu'avec 'exec',' x' finit en effet dans 'globals' et' locals'; Au début, je pensais que les deux produiraient des «globals» et des «locals» identiques. Mais, oui, pourquoi ne se penche-t-il pas sur 'locals', et pourquoi' eval ("x") 'fonctionne-t-il, où' x' échoue? –

+2

Je pense que la portée d'une variable dans une fonction est déterminée au moment de la définition. Ainsi, des choses comme 'a =" a "; def print_a(): imprime (a); a = "c" 'lancera un UnboundLocalError. 'eval (" x ")' "crée une nouvelle recherche complète" et peut donc regarder dans la portée locale. – syntonym

+0

@syntonym C'est une théorie intéressante qui a du sens, compte tenu de votre exemple, et pourrait expliquer le comportement. Pouvez-vous fournir une référence pour cela? –