Contrairement à d'autres réponses déjà postées, vous ne pouvez pas modifier locals()
directement et s'attendre à ce que cela fonctionne.
>>> def foo():
lcl = locals()
lcl['xyz'] = 42
print(xyz)
>>> foo()
Traceback (most recent call last):
File "<pyshell#6>", line 1, in <module>
foo()
File "<pyshell#5>", line 4, in foo
print(xyz)
NameError: global name 'xyz' is not defined
Modifier locals()
est indéfinie. En dehors d'une fonction, lorsque locals()
y globals()
sont identiques, cela fonctionnera ; à l'intérieur d'une fonction, cela fonctionnera généralement ne fonctionne pas.
Utilisez un dictionnaire, ou définissez un attribut sur un objet :
d = {}
d['xyz'] = 42
print(d['xyz'])
ou si vous préférez, utilisez une classe :
class C: pass
obj = C()
setattr(obj, 'xyz', 42)
print(obj.xyz)
Modifier : L'accès aux variables des espaces de noms qui ne sont pas des fonctions (donc les modules, les définitions de classes, les instances) se fait généralement par consultation de dictionnaires (comme le souligne Sven dans les commentaires, il y a des exceptions, par exemple les classes qui définissent __slots__
). Les fonctions locales peuvent être optimisées en termes de vitesse car le compilateur connaît (généralement) tous les noms à l'avance, de sorte qu'il n'y a pas de dictionnaire jusqu'à ce que vous appeliez locals()
.
Dans l'implémentation C de Python locals()
(appelé à l'intérieur d'une fonction) crée un dictionnaire ordinaire initialisé à partir des valeurs courantes des variables locales. Dans chaque fonction, un nombre quelconque d'appels à locals()
retournera le même dictionnaire, mais chaque appel à locals()
le mettra à jour avec les valeurs actuelles des variables locales. Cela peut donner l'impression que les affectations aux éléments du dictionnaire sont ignorées (j'avais initialement écrit que c'était le cas). Les modifications des clés existantes dans le dictionnaire retourné par la fonction locals()
ne durent donc que jusqu'au prochain appel à locals()
dans le même périmètre.
Dans IronPython, les choses fonctionnent un peu différemment. Toute fonction qui appelle locals()
à l'intérieur, il utilise un dictionnaire pour ses variables locales, donc les affectations aux variables locales modifient le dictionnaire et les affectations au dictionnaire modifient les variables. MAIS c'est seulement si vous appelez explicitement locals()
sous ce nom. Si vous liez un nom différent à la locals
dans IronPython, alors l'appeler vous donne les variables locales de la portée où le nom a été lié et il n'y a aucun moyen d'accéder aux locales de la fonction à travers elle :
>>> def foo():
... abc = 123
... lcl = zzz()
... lcl['abc'] = 456
... deF = 789
... print(abc)
... print(zzz())
... print(lcl)
...
>>> zzz =locals
>>> foo()
123
{'__doc__': None, '__builtins__': <module '__builtin__' (built-in)>, 'zzz': <built-in function locals>, 'foo': <function foo at 0x000000000000002B>, '__name__': '__main__', 'abc': 456}
{'__doc__': None, '__builtins__': <module '__builtin__' (built-in)>, 'zzz': <built-in function locals>, 'foo': <function foo at 0x000000000000002B>, '__name__': '__main__', 'abc': 456}
>>>
Tout cela peut changer à tout moment. La seule chose garantie est que vous ne pouvez pas dépendre des résultats de l'assignation au dictionnaire retourné par locals()
.
2 votes
Vous vous y prenez mal si le nom de la variable est dynamique.
17 votes
J'ai déjà programmé la lecture des noms d'espèces chimiques à partir d'un fichier d'entrée, puis la création d'objets pour ces noms d'espèces à partir de ce que j'ai lu dans le fichier texte. De cette façon, je peux dire H2O.mwt, quelque chose comme ça. Il pourrait y avoir une raison légitime de faire cela, IMHO.
1 votes
Je suis conscient que c'est une mauvaise pratique. Mais dans certaines conditions, cela peut être un sale raccourci. De plus, c'est intéressant, cela montre à quel point le langage peut être dynamique. C'est aussi une bonne chose que le feedback soit ici pour que les lecteurs ne l'utilisent pas facilement, mais ce n'est pas une raison valable pour un vote négatif.
6 votes
Le tableau des locals rapides est couplé à l'objet code (i.e. co_varnames, co_nlocals). C'est corrigé.
locals()
c'est juste appeler PyFrame_FastToLocals pour créer une vue dictée des valeurs actuelles. Vous pouvez mettre à jour dynamiquement les locales rapides sur la base de ce dict si vous utilisezctypes
d'appeler PyFrame_LocalsToFast sur le cadre actuel (sys._getframe(0)
).1 votes
@eryksun - cela ressemble au début d'une réponse complète et perspicace - si vous voulez la compiler en une seule, je l'accepterai.
1 votes
@Jonathan : Utiliser l'API C n'est pas une bonne solution. Elle vous permet de mettre à jour dynamiquement un local dans une fonction (je ne vois pas l'intérêt d'en créer un) dans Python 2 et 3, mais c'est 'hacky'. Même la réponse de @kindall ne fonctionne pas dans Python 3 (le bytecode compilé utilise toujours
LOAD_GLOBAL
). Pour autant que je sache, il n'y a eu aucune tentative pour faciliter cela de manière standard.