35 votes

globaux et locaux en python exec ()

Je suis en train d'exécuter un morceau de code python en utilisant exec.

my_code = """
class A(object):
  pass

print 'locals: %s' % locals()
print 'A: %s' % A

class B(object):
  a_ref = A
"""

global_env = {}
local_env = {}
my_code_AST = compile(my_code, "My Code", "exec")
exec(my_code_AST, global_env, local_env)

print local_env

ce qui entraîne la sortie suivante

locals: {'A': <class 'A'>}
A: <class 'A'>
Traceback (most recent call last):
  File "python_test.py", line 16, in <module>
    exec(my_code_AST, global_env, local_env)
  File "My Code", line 8, in <module>
  File "My Code", line 9, in B
NameError: name 'A' is not defined

Cependant, si je change le code de cette -

my_code = """
class A(object):
  pass

print 'locals: %s' % locals()
print 'A: %s' % A

class B(A):
  pass
"""

global_env = {}
local_env = {}
my_code_AST = compile(my_code, "My Code", "exec")
exec(my_code_AST, global_env, local_env)

print local_env

puis il fonctionne très bien - en donnant la sortie suivante -

locals: {'A': <class 'A'>}
A: <class 'A'>
{'A': <class 'A'>, 'B': <class 'B'>}

Clairement Un est présent et accessible - ce qui ne va pas dans le premier morceau de code? Je suis en utilisant 2.6.5, cheers,

Colin

* Mise à JOUR de 1 *

Si je coche locals() à l'intérieur de la classe -

my_code = """
class A(object):
  pass

print 'locals: %s' % locals()
print 'A: %s' % A

class B(object):
  print locals()
  a_ref = A
"""

global_env = {}
local_env = {}
my_code_AST = compile(my_code, "My Code", "exec")
exec(my_code_AST, global_env, local_env)

print local_env

Puis il devient clair que les gens du pays() n'est pas la même dans les deux lieux -

locals: {'A': <class 'A'>}
A: <class 'A'>
{'__module__': '__builtin__'}
Traceback (most recent call last):
  File "python_test.py", line 16, in <module>
    exec(my_code_AST, global_env, local_env)
  File "My Code", line 8, in <module>
  File "My Code", line 10, in B
NameError: name 'A' is not defined

Cependant, si je fais cela, il n'y a pas de problème -

def f():
  class A(object):
    pass

  class B(object):
    a_ref = A

f()

print 'Finished OK'

* Mise à JOUR 2 *

ok, donc les docs ici - http://docs.python.org/reference/executionmodel.html

"Une définition de classe est un exécutable énoncé qui peut utiliser et définir des noms. Ces références suivent les règles normales pour la résolution de nom. L'espace de noms de la définition de la classe devient l'attribut dictionnaire de la classe. Les noms définis à l'étendue de classe ne sont pas visibles dans les méthodes.'

Il me semble que " A " doit être mis à la disposition gratuitement de la variable dans le fichier exécutable énoncé de la définition de B, et lorsque cela se produit, nous appelons f() ci-dessus, mais pas quand nous utiliser exec(). Cela peut être plus facilement illustré par la suivante -

my_code = """
class A(object):
  pass

print 'locals in body: %s' % locals()
print 'A: %s' % A

def f():
  print 'A in f: %s' % A

f()

class B(object):
  a_ref = A
"""

les sorties qui

locals in body: {'A': <class 'A'>}
A: <class 'A'>
Traceback (most recent call last):
  File "python_test.py", line 20, in <module>
    exec(my_code_AST, global_env, local_env)
  File "My Code", line 11, in <module>
  File "My Code", line 9, in f
NameError: global name 'A' is not defined

Donc je suppose que la nouvelle question est pourquoi ne sont pas les habitants d'être exposées comme des variables libres dans des fonctions et des définitions de classe -, il semble comme une jolie fermeture standard scénario.

18voto

Roee Shenberg Points 417

Eh bien, je crois que c'est une mise en œuvre bug ou d'une sans-papiers décision de conception. Le nœud de la question est un nom de liaison de l'opération dans le module-champ d'application doit se lier à une variable globale. La façon dont il est atteint est que, lorsque dans le module de niveau, globals() EST locals() (essayez que l'un dans l'interpréteur), de sorte que lorsque vous faites n'importe quel nom de liaison, il l'attribue, comme d'habitude, pour les gens du coin() dictionnaire, qui est aussi le globals, d'où une variable globale est créée.

Lorsque vous recherchez une variable, vous devez d'abord vérifier votre actuelle habitants, et si le nom n'est pas trouvé, vous récursive vérifier les habitants de contenant étendues pour le nom de la variable jusqu'à ce que vous trouver la variable ou de la portée du module-portée. Si vous arrivez à vous que vous vérifiez les variables globales, qui sont censés être à la portée de module habitants.

>>> exec(compile("import sys\nprint sys._getframe().f_code.co_name", "blah", "exec"), {}, {})
<module>
>>> exec("a = 1\nclass A(object):\n\tprint a\n", {}, {})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 2, in <module>
  File "<string>", line 3, in A
NameError: name 'a' is not defined
>>> d = {}
>>> exec("a = 1\nclass A(object):\n\tprint a\n", d,d)
1

Ce comportement est pourquoi l'héritage de travail (Le nom de la recherche de code de l'objet de la portée des habitants(), qui en effet avait en elle).

En fin de compte, c'est un vilain hacker dans le Disponible de la mise en œuvre, spécial-boîtier globals de recherche. Il provoque aussi quelques absurde artificielle situations - par exemple:

>>> def f():
...     global a
...     a = 1
...
>>> f()
>>> 'a' in locals()
True

Veuillez noter que tout est de ma inférence basée sur déconner avec l'interprète lors de la lecture de l'article 4.1 (Nommage et de liaison) de la référence au langage python. Si ce n'est pas définitive (je n'ai pas encore ouvert Disponible sources), je suis assez sûr que je suis correct sur le comportement.

8voto

Zoe Points 31

Après print locals() et globals() , vous trouverez la raison pour laquelle exec lève une exception "non définie", et vous pouvez essayer ceci

 d = dict(locals(), **globals())
exec (code, d, d)
 

2voto

Don Kirkby Points 12671

Si votre question est de savoir comment obtenir que l'instruction exec se comporte comme la portée du fichier, j'ai suivi quelques conseils dans la question et le bug liés et je l'ai fait fonctionner en passant un seul dictionnaire pour les globaux et les locaux. Apparemment, la portée du fichier est un cas spécial où les déclarations locales sont automatiquement placées dans la portée globale.

 exec code in dict()
 

2voto

my_code = """
class A(object):
    pass

class B(object):
    a = A
"""

my_code_AST = compile(my_code, "My Code", "exec")
extra_global = "hi"
global_env = {}
exec my_code_AST in global_env
print "global_env.keys() =", global_env.keys()
print "B.a =", global_env["B"].a

imprime

global_env.keys() = ['__builtins__', 'A', 'B']
B.a = <class 'A'>

Hawkett, dites-vous,

la principale raison que j'ai voulu utiliser les habitants comme ça, était d'obtenir tous les trucs que définies dans le code de la chaîne, sans tous les autres trucs que python met dans les variables globales.

Avec exec, si votre globals n'ont pas d' __builtins__ défini, exec ajoute un élément, __builtins__ de votre globals, de sorte que vous obtenir A, B, et __builtins__. __builtins__ lui-même est un gros dictionnaire, mais c'est toujours le même élément à supprimer (aussi longtemps que vous attendez que votre code est fini de l'utiliser avant de le supprimer!). Documenté en vertu de l'exec() ici.

Les docs pour eval sous construit dans les fonctions de dire

Si le globals dictionnaire est présent et le manque d‘"objets internes", l'globales sont copiés dans globals avant d'expression est analysée.

Mais en réalité, il semble que de copier __builtins__ dans.

(Et n.b. ce que tout le monde dit: soit définir les variables globales et locales de la même ou de dire exec my_code_AST in global_env sans local_env.)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X