Compte tenu du code suivant:
def A() :
b = 1
def B() :
# I can access 'b' from here.
print( b )
# But can i modify 'b' here? 'global' and assignment will not work.
B()
A()
Pour le code dans la B()
variable de fonction b
est dans la portée externe, mais pas dans la portée globale. Est-il possible de modifier la b
variable à partir de la B()
fonction? Je peux sûrement le lire d'ici et print()
, mais comment le modifier?
python
python-2.7
grigoryvp
la source
la source
b
est mutable. Une affectation àb
masquera la portée extérieure.nonlocal
n'a pas été rétroporté à 2.x. C'est une partie intrinsèque du support de fermeture.Réponses:
Python 3.x a le
nonlocal
mot - clé . Je pense que cela fait ce que vous voulez, mais je ne sais pas si vous utilisez python 2 ou 3.Pour python 2, j'utilise généralement simplement un objet mutable (comme une liste ou un dict), et je mute la valeur au lieu de réaffecter.
exemple:
Les sorties:
la source
class nonlocal: pass
dans la portée externe. Ensuite,nonlocal.x
peut être affecté dans la portée interne.SyntaxError
. PeutNonLocal
- être ?Nonlocal
,? :-)Vous pouvez utiliser une classe vide pour contenir une portée temporaire. C'est comme le mutable mais un peu plus joli.
Cela donne la sortie interactive suivante:
la source
Je suis un peu nouveau dans Python, mais j'ai lu un peu à ce sujet. Je pense que le mieux que vous obtiendrez est similaire à la solution de contournement Java, qui consiste à envelopper votre variable externe dans une liste.
Edit: Je suppose que c'était probablement vrai avant Python 3. On dirait que
nonlocal
c'est votre réponse.la source
Non, vous ne pouvez pas, du moins de cette manière.
Parce que l '"opération set" créera un nouveau nom dans la portée actuelle, qui couvre le nom extérieur.
la source
Pour quiconque regarde cela beaucoup plus tard, une solution de contournement plus sûre mais plus lourde est. Sans avoir besoin de passer des variables comme paramètres.
la source
La réponse courte qui fonctionnera automatiquement
J'ai créé une bibliothèque python pour résoudre ce problème spécifique. Il est publié sous la dissidence, alors utilisez-le comme vous le souhaitez. Vous pouvez l'installer avec
pip install seapie
ou consulter la page d'accueil ici https://github.com/hirsimaki-markus/SEAPIEuser@pc:home$ pip install seapie
les sorties
les arguments ont la signification suivante:
B()
, 1 signifie parentA()
et 2 signifierait grand-parent<module>
aka globalLa longue réponse
C'est plus compliqué. Seapie fonctionne en éditant les cadres dans la pile d'appels à l'aide de l'API CPython. CPython est la norme de facto, donc la plupart des gens n'ont pas à s'en soucier.
Les mots magiques qui vous intéressent probablement le plus si vous lisez ceci sont les suivants:
Ce dernier forcera les mises à jour à passer dans la portée locale. Les portées locales sont cependant optimisées différemment de la portée globale, de sorte que l'introduction de nouveaux objets pose quelques problèmes lorsque vous essayez de les appeler directement s'ils ne sont initialisés d'aucune façon. Je vais copier quelques moyens de contourner ces problèmes à partir de la page github
Si vous pensez que l'utilisation
exec()
n'est pas quelque chose que vous voulez utiliser, vous pouvez émuler le comportement en mettant à jour le vrai dictionnaire local (et non celui renvoyé par les locaux ()). Je vais copier un exemple de https://faster-cpython.readthedocs.io/mutable.htmlProduction:
la source
Je ne pense pas que tu devrais vouloir faire ça. Les fonctions qui peuvent modifier les choses dans leur contexte englobant sont dangereuses, car ce contexte peut être écrit à l'insu de la fonction.
Vous pouvez le rendre explicite, soit en faisant de B une méthode publique et C une méthode privée dans une classe (le meilleur moyen probablement); ou en utilisant un type mutable tel qu'une liste et en le passant explicitement à C:
la source
nonlocal
mot-clé - mais c'est à vous de l'utiliser avec beaucoup de prudence.Vous pouvez, mais vous devrez utiliser la déclaration globale (ce n'est pas une très bonne solution comme toujours lorsque vous utilisez des variables globales, mais cela fonctionne):
la source
Je ne sais pas s'il y a un attribut d'une fonction qui donne le
__dict__
de l'espace extra-atmosphérique de la fonction quand cet espace extérieur n'est pas l'espace global == le module, ce qui est le cas lorsque la fonction est une fonction imbriquée, en Python 3.Mais dans Python 2, pour autant que je sache, il n'y a pas un tel attribut.
Donc, les seules possibilités pour faire ce que vous voulez sont:
1) utiliser un objet mutable, comme l'ont dit d'autres
2)
résultat
.
Nota
La solution de Cédric Julien présente un inconvénient:
résultat
Le b global après exécution de
A()
a été modifié et il peut ne pas être souhaité ainsiC'est le cas uniquement s'il y a un objet avec l'identifiant b dans l'espace de noms global
la source