web-dev-qa-db-fra.com

Fonctions locales dans Python

Dans ce qui suit Python code, j'obtiens un UnboundLocalError. Si je comprends bien, les fonctions locales partagent les variables locales de la fonction contenant, mais cela ne semble guère être le cas ici Je reconnais que a est une valeur immuable dans ce contexte, mais cela ne devrait pas poser de problème.

def outer():
    a = 0
    def inner():
        a += 1
    inner()
outer()

Il semblerait que la fonction interne ait reçu des copies de toutes les références dans la fonction parent, car je n'obtiens pas l'exception UnboundLocalError si la valeur de a est enveloppée dans un type mutable.

Est-ce que quelqu'un est capable de clarifier le comportement ici, et de me diriger vers la documentation appropriée Python à ce sujet?)

34
Matt Joiner

Je crois que vous avez raison de voir cela comme un problème de "mutabilité". Alors que le code que vous avez publié lève un "UnboundLocalError", le code suivant ne le fait pas:

def outer():
    a = 0
    def inner():
        print a
    inner()
outer()

Python ne vous permet pas de réaffecter la valeur d'une variable à partir d'une portée externe dans une portée interne (sauf si vous utilisez le mot-clé "global", qui ne s'applique pas dans ce cas).

Consultez la section inférieure de la documentation "classes" dans cette Python 2.6.2:

9.2. Python Portées et espaces de noms

[…] Si un nom est déclaré global, toutes les références et affectations vont directement à la portée intermédiaire contenant les noms globaux du module. Sinon, toutes les variables trouvées en dehors de la portée la plus interne sont en lecture seule (une tentative d'écriture dans une telle variable créera simplement une nouvelle variable locale dans la portée la plus interne, laissant inchangée la variable externe nommée de manière identique).

Votre "UnboundLocalError" est dû au fait que votre fonction déclare en fait une nouvelle variable appelée "a", puis essaie immédiatement d'effectuer une opération "+ =" dessus, mais cela échoue car "a" n'a pas encore de valeur. (Regardez le "a + = 1" comme "a = a + 1" et vous pouvez voir le problème si "a" n'est pas défini).

En général, si vous voulez modifier "a", la façon dont les gens le contournent est d'utiliser un type mutable pour passer "a" (comme une liste ou un dictionnaire). Vous pouvez modifier "a" via le contenu du type mutable (comme vous l'avez probablement remarqué lors de vos tests avec cette configuration).

J'espère que cela pourra aider!

31
Brent Writes Code

Vous devez spécifier votre variable comme non locale pour conserver son état en fermeture, donc la définition devrait être comme ceci

def outer():
a = 0
def inner():
    nonlocal a
    a += 1
inner()
11
vaduha

Essayez de lier la variable en tant qu'argument.

def outer():
    a = 0
    def inner(a=a):
        a += 1

    inner()

outer()

Je vais essayer de déterrer les documents appropriés.

modifier

Puisque vous voulez que la fonction interne ait un effet secondaire sur la portée externe, vous devez utiliser un type de données mutable comme une liste. Les entiers et les chaînes sont immuables.

def outer():
    a = [0]
    def inner():
        a[0] += 1
    inner()
    print a[0]
outer()
9
Unknown