Quelle est la portée d'une variable initialisée dans une instruction if?

266

Je suis nouveau sur Python, c'est donc probablement une question de portée simple. Le code suivant dans un fichier Python (module) m'embrouille légèrement:

if __name__ == '__main__':
    x = 1

print x

Dans d'autres langages dans lesquels j'ai travaillé, ce code lèverait une exception, car la xvariable est locale à l' ifinstruction et ne devrait pas exister en dehors d'elle. Mais ce code s'exécute et imprime 1. Quelqu'un peut-il expliquer ce comportement? Toutes les variables créées dans un module sont-elles globales / disponibles pour l'ensemble du module?

froadie
la source
17
Une autre bizarrerie que vous ne connaissez peut-être pas: si la ifdéclaration ci-dessus n'est pas vraie (c'est-à- __name__dire qu'elle ne l' est pas'__main__' , par exemple lorsque vous importez le module au lieu de l'exécuter au niveau supérieur), alors elle xn'aura jamais été liée et la print xdéclaration suivante jettera un NameError: name 'x' is not defined.
Santa

Réponses:

302

Les variables Python sont limitées à la fonction, à la classe ou au module le plus interne auquel elles sont affectées. Les blocs de contrôle comme ifet les whileblocs ne comptent pas, donc une variable assignée à l'intérieur d'unif est toujours étendue à une fonction, une classe ou un module.

(Fonctions implicites définies par une expression de générateur ou d'une liste / set / dict compréhension faire nombre, tout comme lambda expressions. Vous ne pouvez pas farcir une instruction d'affectation dans l' un de ceux, mais les paramètres lambda et les forobjectifs de la clause sont cession implicite.)

Luke Maurer
la source
1
@ chandr3sh docs.python.org/3/tutorial/…
Fakher Mokadem
105

Oui, ils sont dans la même "portée locale", et en fait, un code comme celui-ci est courant en Python:

if condition:
  x = 'something'
else:
  x = 'something else'

use(x)

Notez que ce xn'est pas déclaré ou initialisé avant la condition, comme ce serait en C ou Java, par exemple.

En d'autres termes, Python n'a pas d'étendues au niveau du bloc. Soyez prudent, cependant, avec des exemples tels que

if False:
    x = 3
print(x)

ce qui soulèverait clairement une NameErrorexception.

Eli Bendersky
la source
42

La portée en python suit cet ordre:

  • Rechercher la portée locale

  • Rechercher l'étendue de toutes les fonctions englobantes

  • Rechercher la portée mondiale

  • Rechercher les intégrés

( source )

Notez que ifet d'autres constructions en boucle / ramification ne sont pas répertoriées - seules les classes, fonctions et modules fournissent une portée en Python, donc tout ce qui est déclaré dans un ifbloc a la même portée que tout ce qui a été effacé en dehors du bloc. Les variables ne sont pas vérifiées au moment de la compilation, c'est pourquoi d'autres langages lèvent une exception. En python, tant que la variable existe au moment où vous en avez besoin, aucune exception ne sera levée.

Daniel G
la source
9

Comme l'a dit Eli, Python ne nécessite pas de déclaration de variable. En C, vous diriez:

int x;
if(something)
    x = 1;
else
    x = 2;

mais en Python, la déclaration est implicite, donc lorsque vous l'assignez à x, elle est automatiquement déclarée. C'est parce que Python est typé dynamiquement - cela ne fonctionnerait pas dans un langage typé statiquement, car selon le chemin utilisé, une variable pourrait être utilisée sans être déclarée. Cela serait intercepté au moment de la compilation dans une langue typée statiquement, mais avec une langue typée dynamiquement, cela est autorisé.

La seule raison pour laquelle un langage typé statiquement se limite à devoir déclarer des variables en dehors des ifinstructions à cause de ce problème. Embrassez la dynamique!

Skilldrick
la source
9

Contrairement aux langages tels que C, une variable Python est à la portée de l'ensemble de la fonction (ou classe ou module) où elle apparaît, et pas seulement dans le "bloc" le plus intérieur. C'est comme si tu avais déclaréint x en haut de la fonction (ou classe, ou module), sauf qu'en Python vous n'avez pas à déclarer de variables.

Notez que l'existence de la variable xn'est vérifiée qu'au moment de l'exécution, c'est-à-dire lorsque vous accédez à l' print xinstruction. Si __name__n'égalait "__main__"alors vous faire une exception: NameError: name 'x' is not defined.

Paul Stephenson
la source
Les classes ne créent pas de portée; une variable "locale" dans une classe est simplement ajoutée au dict de la classe lors de sa création.
chepner
3

Oui. C'est également vrai pour la forportée. Mais pas de fonctions bien sûr.

Dans votre exemple: si la condition dans l' ifinstruction est fausse, xelle ne sera cependant pas définie.

Olivier Verdier
la source
2

vous exécutez ce code à partir de la ligne de commande, les ifconditions sont donc vraies et xdéfinies. Comparer:

>>> if False:
    y = 42


>>> y
Traceback (most recent call last):
  File "<pyshell#6>", line 1, in <module>
    y
NameError: name 'y' is not defined
SilentGhost
la source
0

Et notez que puisque les types Python ne sont vérifiés qu'au moment de l'exécution, vous pouvez avoir du code comme:

if True:
    x = 2
    y = 4
else:
    x = "One"
    y = "Two"
print(x + y)

Mais j'ai du mal à penser à d'autres façons dont le code fonctionnerait sans erreur en raison de problèmes de type.

Cowang
la source