python的作用域问题
高洛峰
高洛峰 2017-04-18 09:29:09
0
4
739
x = 3
y = [3]

def test1():
    x += 1
    print x

def test2():
    y[0] = 4
    y.append(5)
    print y

test2()
test1()

这段代码执行结果: test2()成功打印[4, 5], test1()却报错: UnboundLocalError: local variable 'x' referenced before assignment

想不明白,为什么会这样,全局变量在函数里可以直接打印,但是如果要改变它的值,会报错,但是test2()为什么不报错?如果把y换成dict类型,就能在函数里不需要用global声明,可以直接改变y的值,但如果是str或number,就会报错,为什么?

高洛峰
高洛峰

拥有18年软件开发和IT教学经验。曾任多家上市公司技术总监、架构师、项目经理、高级软件工程师等职务。 网络人气名人讲师,...

répondre à tous(4)
洪涛

En fait, cette question peut être mise de côté si l'objet référencé par la variable est mutable ou immuable. Ce à quoi nous devons prêter attention, c'est le positionnement de la variable, le moment et la portée de. la définition.

Considérez le code suivant :

def test(a):
    print(a)
    print(b)
    
test(1)

Ce code générera une erreur :

1
Traceback (most recent call last):
  File "tp.py", line 5, in <module>
    test(1)
  File "tp.py", line 3, in test
    print(b)
NameError: name 'b' is not defined

a est la variable param de la fonction test, elle appartient donc à une variable locale, et sa portée est la fonction test Nous passons 1 pour a auquel faire référence, donc il n'y a pas de gros problème. avec print(a).
Mais b n'est pas défini du début à la fin. Même si vous recherchez selon le principe LEGB, vous ne le trouvez pas, vous relancez donc un NameError.

Pour résoudre ce problème, peut-être pouvons-nous définir une variable globale :

b = 100

def test(a):
    print(a)
    print(b)
    
test(1)

Bien, cette fois il ne semble y avoir aucun problème, car Python a trouvé b dans le cadre de global La raison pour laquelle Python utilise global b est parce que nous n'avons pas défini b en local.

Ensuite, nous commençons à attribuer des variables dans la fonction :

b = 100

def test(a):
    b = 20
    print(a)
    print(b)
    
test(1)
print(b)

Résultat :

1
20
100

Les deux print dans la fonction ont imprimé 1 et 20 sans surprise, mais pourquoi la valeur de b imprimée après avoir quitté la fonction était-elle de 100 ?
Parce que nous avons écrit cela dans la fonction A l'affectation est également une définition b = 20, donc les test vus dans b sont tous locaux, pas globaux, donc toutes les modifications que nous apportons à b Aucune modification n'affectera le b global. 🎜>.

Cela nous dit :

Lorsque la variable locale n'est pas définie, Python utilisera automatiquement la variable globale, sinon elle ne le fera pas

Alors comment pouvons-nous opérer des variables globales au sein de la fonction ? Cela nécessite l'aide du mot-clé global :

b = 100

def test(a):
    global b
    b = 20
    print(a)
    print(b)
    
test(1)
print(b)
1
20
20

Avec le mot-clé global décrivant b, Python traitera le test dans b comme une variable d'accès au b global et b = 20 ne sera traité que comme une action d'affectation ne définit pas de nouvelle variable locale.

Regardons un exemple plus déroutant :

b = 100

def test(a):
    print(a)
    print(b)
    b = 20
    
test(1)
print(b)

Résultat :

1
Traceback (most recent call last):
  File "tp.py", line 8, in <module>
    test(1)
  File "tp.py", line 5, in test
    print(b)
UnboundLocalError: local variable 'b' referenced before assignment

apparaît ici UnboundLocalError, pourquoi cela se produit-il ? La raison est très simple, b a une action d'affectation et de définition dans cette fonction : b = 20, donc les test à l'intérieur de b sont locaux (globaux n'est pas utilisé ici pour indiquer que b est global), donc lorsque print(b) est utilisé, Python essaiera de récupérer local b au lieu de global b, mais la tragédie est qu'ici Dans la première étape, local b n'a pas été attribué, on dit donc que local variable 'b' referenced before assignment a été référencé avant d'être attribué, ce qui n'est naturellement pas possible.

Regardez l'exemple que vous avez donné :

x = 3

def test1():
    x += 1
    print x

Ici, la définition de test1 apparaît dans x (il n'y a pas de global, et x apparaît à gauche du signe égal. Naturellement, lorsque vous faites référence à x, vous voudrez). utilisez local, mais parce que :

x += 1 等義 x = x + 1

Donc, lorsque vous souhaitez obtenir la valeur référencée par x à droite du signe égal, vous constatez qu'aucune valeur ne lui a encore été attribuée. Alors c'est la même chose que l'exemple ci-dessus :

UnboundLocalError: local variable 'x' referenced before assignment

Quant à votre test2 il n'y aura aucun problème :

y = [3]

def test2():
    y[0] = 4
    y.append(5)
    print y

est parce que y n'apparaît pas à gauche du signe égal dans test2, donc Python suppose automatiquement que global y est utilisé, donc naturellement il n'y a pas de problème

!

Conclusion

  1. Pour voir si une variable locale est définie dans une fonction, vérifiez si le nom de la variable apparaît à gauche du signe égal et si le nom de la variable n'est pas spécifié par global

  2. Si une variable locale est définie, Python ne recherchera pas de variable globale, sinon Python utilisera automatiquement la variable globale

  3. Si une variable locale est définie mais que vous lisez la référence avant que la variable ne soit attribuée, une UnboundLocalError apparaîtra

  4. Pour résoudre ce problème, pensez à ajouter global pour indiquer l'intégralité du domaine, sinon cette méthode d'écriture ne devrait pas apparaître (opération sur place, ou affectation ultérieure)

  5. Des problèmes similaires se produiront également dans les fonctions locales. La solution est d'ajouter nonlocal (Python3), mais c'est une autre histoire.


Questions auxquelles j'ai répondu : Python-QA

洪涛

La portée des variables de Python est stipulée de cette manière. Dans test1, vous pouvez print x mais ne pouvez pas modifier x
Certaines personnes disent que "les variables globales dans la portée locale doivent être en lecture seule", mais ce n'est pas vrai pour variables de référence. . .

Cet endroit en python est vraiment déroutant

Peter_Zhu

En termes simples, la liaison des variables globales ne peut pas être modifiée dans la portée locale et l'adresse de la variable ne peut pas être modifiée dans CPython.

Voir : Erreur courante 4 dans : Les dix erreurs les plus courantes commises par les programmeurs Python : mauvaise compréhension de l'analyse des noms de variables en Python

伊谢尔伦

Votre fonction test1 a une opération d'affectation x += 1, qui est considérée par l'interpréteur Python comme une variable dans la portée locale de la fonction. Cependant, la variable x n'est pas définie avant l'affectation, et x est number, appartient au type immuable. Pour attribuer de nouvelles valeurs au type immuable, vous devez recréer un objet de type immuable et rediriger la variable d'origine vers l'objet nouvellement créé, mais cela l'objet nouvellement créé n'est pas inclus dans LEGB Introuvable, donc une erreur sera signalée

Dans la fonction

test2, y est un list, qui est un type de variable. La liste pointe toujours vers la même adresse mémoire après l'ajout, car la liste est un type de variable et peut être modifiée sur place. , cela ne signale pas d'erreur

Toutes les opérations d'affectation dans

Python sont essentiellement divisées en trois étapes suivantes (en prenant a = 3 comme exemple) :

  1. Créer un objet pour représenter la valeur3

  2. Créer une variable a, si elle n'a pas encore été créée

  3. Connectez la variable a au nouvel objet 3

Observons les changements d'adresse mémoire de la variable test2 lors de l'exécution de votre y fonction

y = [3]
print(id(y))
def test2():
    y[0] = 4
    print(id(y))
    y.append(5)
    print(id(y))
    print(y)
    
test2()
x = 3
print(id(x))
x = 4
print(id(x))

Sortie

79051032
79051032
79051032
[4, 5]
1375754544
1375754560

Vous pouvez voir que y est en fait modifié sur place, il n'est donc pas nécessaire de créer des variables à plusieurs reprises ; et pour le type immuable x, pour lui attribuer une valeur, vous devez d'abord créer un nouvel objet, même si le nom Identique, vous pouvez voir que si des affectations différentes sont effectuées à chaque fois, l'adresse mémoire de x est en fait différente, ce qui peut aussi expliquer pourquoi str ou number signaleront une erreur

Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!