UnboundLocalError en Python [dupliquer]

cette question a déjà une réponse ici:

Qu'est-ce que je fais de mal ici?

counter = 0

def increment():
  counter += 1

increment()

le code ci-dessus lance un UnboundLocalError .

108
demandé sur igaurav 2012-02-13 21:11:38

8 réponses

Python n'a pas de déclarations de variables, il doit donc comprendre le scope de variables lui-même. Il le fait par une règle simple: S'il y a une affectation à une variable à l'intérieur d'une fonction, cette variable est considérée comme locale. [1] ainsi ,la ligne

counter += 1

rend implicitement counter local à increment() . Essayez d'exécuter cette ligne, cependant, essayez de lire le valeur de la variable locale counter avant son attribution, résultant en un UnboundLocalError . [2]

si counter est une variable globale, le mot-clé global aidera. Si increment() est une fonction locale et counter une variable locale, vous pouvez utiliser nonlocal en Python 3.x.

116
répondu Sven Marnach 2013-02-23 08:24:49

vous devez utiliser le global statement de sorte que vous modifiez le compteur de variables global, au lieu d'une variable locale:

counter = 0

def increment():
  global counter
  counter += 1

increment()

si le champ d'application qui contient la définition de counter n'est pas le champ d'application global, on Python 3.x vous pouvez utiliser le déclaration non locale . Dans la même situation sur Python 2.x vous n'auriez aucun moyen de réattribuer au nom non local counter , donc vous auriez besoin de faire counter mutable et le modifier:

counter = [0]

def increment():
  counter[0] += 1

increment()
print counter[0]  # prints '1'
62
répondu Andrew Clark 2012-02-13 17:20:10

pour répondre à la question dans votre ligne d'objet,* oui, il y a des fermetures en Python, sauf qu'elles ne s'appliquent qu'à l'intérieur d'une fonction, et aussi (en Python 2.x) ils sont en lecture seule; vous ne pouvez pas re-lier le nom à un objet différent (bien que si l'objet est mutable, vous pouvez modifier son contenu). En Python 3.x, vous pouvez utiliser le mot-clé nonlocal pour modifier une variable de fermeture.

def incrementer():
    counter = 0
    def increment():
        nonlocal counter
        counter += 1
        return counter
    return increment

increment = incrementer()

increment()   # 1
increment()   # 2

* le titre original de la question portait sur les fermetures en Python.

13
répondu kindall 2017-04-07 12:08:20

la raison pour laquelle votre code lance un UnboundLocalError est déjà bien expliquée dans d'autres réponses.

mais il me semble que vous essayez de construire quelque chose qui fonctionne comme itertools.count() .

Alors pourquoi ne pas l'essayer, et voir si elle convient à votre cas:

>>> from itertools import count
>>> counter = count(0)
>>> counter
count(0)
>>> next(counter)
0
>>> counter
count(1)
>>> next(counter)
1
>>> counter
count(2)
6
répondu Rik Poggi 2012-02-13 17:31:13

Pour modifier une variable globale dans une fonction, vous devez utiliser le mot clé global.

quand vous essayez de faire cela sans la ligne

global counter

à l'intérieur de la définition d'incrément, une variable locale nommée counter est créée afin de vous empêcher de salir la variable counter sur laquelle tout le programme peut dépendre.

notez que vous n'avez besoin d'utiliser global que lorsque vous modifiez la variable; vous pouvez lire contrer de l'intérieur increment sans la nécessité de la déclaration globale.

3
répondu chucksmash 2012-02-13 17:13:40

Python a une portée lexicale par défaut, ce qui signifie que bien qu'une portée fermée puisse accéder à des valeurs dans sa portée qui l'entoure, elle ne peut pas les modifier (à moins qu'elles ne soient déclarées globales avec le mot-clé global ).

un dispositif de fermeture lie les valeurs de à l'environnement aux noms de local . L'environnement local peut alors utiliser la valeur liée, et même réaffecter que nom à quelque chose d'autre, mais il ne peut pas modifier la liaison dans l'environnement d'enclos.

Dans votre cas, vous essayez de traiter counter comme une variable locale, plutôt que d'une valeur limite. Notez que ce code, qui lie la valeur de x assignée dans l'environnement environnant, fonctionne très bien:

>>> x = 1

>>> def f():
>>>  return x

>>> f()
1
3
répondu Chris Taylor 2013-02-20 06:43:01

essayez cette

counter = 0

def increment():
  global counter
  counter += 1

increment()
2
répondu Lostsoul 2012-02-13 17:14:50