257 votes

Portée des boucles "for" en Python

Je ne m'interroge pas sur les règles de délimitation du champ d'application de Python. comment Le scoping fonctionne dans les boucles for de Python. Ma question est la suivante pourquoi les décisions de conception ont été prises de cette manière. Par exemple (sans mauvais jeu de mots) :

for foo in xrange(10):
    bar = 2
print(foo, bar)

L'exemple ci-dessus imprimera (9,2).

Cela me semble bizarre : 'foo' ne fait que contrôler la boucle, et 'bar' a été défini à l'intérieur de la boucle. Je peux comprendre pourquoi il est nécessaire que 'bar' soit accessible en dehors de la boucle (sinon, les boucles for auraient une fonctionnalité très limitée). Ce que je ne comprends pas, c'est pourquoi il est nécessaire que la variable de contrôle reste dans la portée après la sortie de la boucle. D'après mon expérience, cela ne fait qu'encombrer l'espace de noms global et rend plus difficile la recherche d'erreurs qui seraient détectées par les interprètes d'autres langues.

12 votes

Si vous ne voulez pas que le for pour éviter d'encombrer votre espace de noms global, intégrez-le dans une fonction. Des fermetures à gogo !

31 votes

À moins que vous n'exécutiez une boucle dans l'espace de noms global (ce qui est peu courant), cela encombre un fichier de type local espace de noms.

4 votes

Si cela n'existait pas, comment continuer le traitement plus tard au point où vous vous êtes arrêté à l'intérieur de la boucle ? Il suffit de définir la variable de contrôle avant la boucle ?

151voto

Jeremy Brown Points 4950

La réponse la plus probable est que cela permet de garder une grammaire simple, que cela n'a pas été une pierre d'achoppement pour l'adoption, et que beaucoup ont été satisfaits de ne pas avoir à désambiguïser la portée à laquelle un nom appartient lorsqu'il lui est assigné dans une construction en boucle. Les variables ne sont pas déclarées à l'intérieur d'une portée, elle est impliquée par l'emplacement des instructions d'affectation. Le site global n'existe que pour cette raison (pour signifier que l'affectation est effectuée à une portée globale).

Mise à jour

Voici une bonne discussion sur le sujet : http://mail.python.org/pipermail/python-ideas/2008-October/002109.html

Propositions antérieures visant à rendre le for-loop locales à la boucle ont se sont heurtées au problème du code existant code existant qui s'appuie sur la variable de la boucle conserve sa valeur après la sortie de la boucle, et il semble que cela soit considérée comme une caractéristique souhaitable.

En bref, vous pouvez probablement en attribuer la responsabilité à la communauté Python :P

3 votes

En quoi la grammaire serait-elle plus compliquée si la portée de la variable d'induction était limitée au corps de la boucle ? Un tel changement serait limité à l'analyse sémantique de Python, pas à sa grammaire.

7 votes

Les boucles ne sont pas des blocs en Python. Ce genre de changement de comportement nécessiterait soit de changer fondamentalement la grammaire, soit de fournir un cas spécial. Le concept entier d'une variable d'induction n'est pas non plus exprimé dans la grammaire actuelle. La grammaire fournit le contrat sur la façon dont l'interpréteur va interpréter. Ce que je veux dire, c'est que je ne vois pas comment modifier ce comportement sans rendre la grammaire plus compliquée. Tout cela est discutable puisque l'effet secondaire de la décision de conception est devenu une fonctionnalité.

1 votes

Ce post ici mail.python.org/pipermail/python-dev/2005-septembre/056677.html donne plus de détails concernant la vitesse et la complication auxquelles M. Brown fait allusion.

79voto

atzz Points 7215

Python n'a pas de blocs, comme certains autres langages (tels que C/C++ ou Java). Par conséquent, l'unité de scoping en Python est une fonction.

5 votes

Je suis confus - qu'est-ce qui empêche Python de délimiter la portée des boucles de la même manière que les fonctions ?

46 votes

Ce n'est pas vraiment vrai, c'est juste que la grammaire ne devient pas folle à cause des blocs. ( docs.python.org/reference/ ) "Un bloc est un morceau de texte de programme Python qui est exécuté en tant qu'unité. Les éléments suivants sont des blocs : un module, un corps de fonction et une définition de classe..."

2 votes

@thebackhand, rien. C'était juste jugé inutile.

52voto

carl Points 25879

A cas vraiment utile pour cela est d'utiliser enumerate et vous voulez le compte total à la fin :

for count, x in enumerate(someiterator, start=1):
    dosomething(count, x)
print "I did something {0} times".format(count)

Est-ce nécessaire ? Non. Mais c'est pratique.

Autre chose à savoir : dans Python 2, les variables dans les compréhensions de listes sont également fuies :

>>> [x**2 for x in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> x
9

Mais, il n'en va pas de même pour Python 3.

4 votes

Vous auriez pu le faire vraisemblablement dans le else clause, c'est-à-dire else: print "I did something {0} times".format(count) - avant la disparition de la portée locale (qui n'existe pas en Python)

3 votes

Seul le deuxième exemple ne fonctionne pas en Python 3, n'est-ce pas ? Le premier fonctionne toujours ? Des notes sur la raison pour laquelle il a été supprimé de Python 3 ?

7 votes

pour count, item dans enumerate(a, start=1) : # l'indice par défaut est de zéro

4voto

kindall Points 60645

L'une des principales influences pour Python est ABC un langage développé aux Pays-Bas pour enseigner les concepts de programmation aux débutants. Le créateur de Python, Guido van Rossum, a travaillé sur ABC pendant plusieurs années dans les années 1980. Je ne sais presque rien d'ABC, mais comme il est destiné aux débutants, je suppose qu'il doit avoir un nombre limité de scopes, un peu comme les premiers BASIC.

-8voto

Kirk Strauser Points 12087

Pour commencer, si les variables étaient locales aux boucles, ces dernières seraient inutiles pour la plupart des programmes du monde réel.

Dans la situation actuelle :

# Sum the values 0..9
total = 0
for foo in xrange(10):
    total = total + foo
print total

donne 45 . Considérons maintenant le fonctionnement de l'affectation en Python. Si les variables de la boucle étaient strictement locales :

# Sum the values 0..9?
total = 0
for foo in xrange(10):
    # Create a new integer object with value "total + foo" and bind it to a new
    # loop-local variable named "total".
    total = total + foo
print total

donne 0 parce que total à l'intérieur de la boucle après l'affectation n'est pas la même variable que total en dehors de la boucle. Ce ne serait pas un comportement optimal ou attendu.

6 votes

Je ne réponds pas à la question. L'OP demandait foo, pas total (ou bar dans leur exemple).

6 votes

@JamesBradbury total y foo Dans le scénario de l'OP, il y aurait toujours des liaisons boucle-local et la logique est la même.

3 votes

OP : "Je peux comprendre pourquoi il pourrait être nécessaire que 'bar' soit accessible en dehors de la boucle (sinon, les boucles for auraient une fonctionnalité très limitée). Ce que je ne comprends pas, c'est pourquoi il est nécessaire pour la boucle for d'être accessible en dehors de la boucle. variable de contrôle pour rester dans le champ d'application après la sortie de la boucle". (c'est moi qui souligne)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X