Pourquoi cela ne crée-t-il pas une boucle infinie?
a=5
for i in range(1,a):
print(i)
a=a+1
ou ca
for i in range(1,4):
print(i)
i=i-1
ou ca
for i in range(1,4):
print(i)
i=1
Existe-t-il un moyen de créer des boucles infinies en utilisant une boucle for
? Je sais qu'il existe une boucle while
pour cela, mais j'étais simplement curieux.
range
est un class , et son utilisation, par ex. range(1, a)
crée un objet de cette classe. Cet objet est créé uniquement une fois , il n'est pas recréé à chaque itération de la boucle. C'est la raison pour laquelle le premier exemple ne donnera pas une boucle infinie.
Les deux autres boucles ne sont pas infinies car, contrairement à l'objet range
, la variable de boucle i
est recréée (ou plutôt réinitialisée ) à chaque itération. Les valeurs que vous affectez à i
à l'intérieur de la boucle seront écrasées à mesure que la boucle itère.
Dans ce cas, vous ne pouvez pas mettre à jour l'itérateur sur lequel votre boucle for
effectue une boucle.
La range
dans for i in range(a):
est en fait une fonction - elle prend une valeur, a, et retourne un objet qui contient les valeurs qu'elle va parcourir en boucle. Une fois que vous avez construit cet objet, vous pouvez modifier la variable d'entrée autant que vous le souhaitez et cet objet ne changera pas.
Imaginons que nous créions notre propre fonction similaire, appelée my_range
, qui génère une liste (alors que la fonction intégrée range
génère une range
):
def my_range(end):
my_list = []
for i in range(end):
my_list.append(i)
return my_list
Maintenant, si nous utilisions notre nouvelle fonction, comme ceci:
a = 4
for i in my_range(a):
print(i)
a += 1
Il serait évident que nous ne pouvons pas mettre à jour l'objet liste sur lequel nous bouclons en changeant a
, car la liste sur laquelle nous bouclons a déjà été créée et n'est pas refaite à chaque boucle.
Pouvez-vous faire une boucle infinie en python? Oui, ajoutez simplement une nouvelle entrée à l'objet que vous parcourez, par exemple:
my_list = [0]
for i in my_list:
print(i)
my_list.append(i+1)
Maintenant, nous mettons à jour l'objet sur lequel nous bouclons.
Prenons une boucle for
name__:
for item in iterable:
print(item)
L'idée est que tant que iterable
reste inchangé, nous allons parcourir chacun des item
dans iterable
une fois. Par exemple,
for item in [3, 2, 1, 666]:
print(item)
affichera 3 2 1 666
. Nous trouvons en particulier que range(1, 4)
est un moyen facile de représenter un [1, 2, 3]
itérable. Ainsi,
for i in range(1, 4):
print(i)
affichera 1 2 3
.
a=5
for i in range(1,a):
print(i)
a=a+1
Dans ce cas, range(1,a)
est évalué une fois , lorsque la boucle commence.
for i in range(1,4):
print(i)
i=i-1
Dans ce cas, i
est réévalué chaque boucle avant d'exécuter les instructions print
et i=i-1
dans le corps de la boucle.
for i in range(1,4):
print(i)
i=1
Tout comme Exemple 2 , i
est réévalué à chaque boucle.
for
boucles et l'objet range(..)
Si vous écrivez for i in range(..):
, Python fait not traduit cela en quelque chose comme for(int i = 0; i < n; i++)
(dans la famille de langages de programmation C).
De plus, l'objet plage est construit une fois, avant la boucle for
. L'objet range(..)
ne sait pas quelles variables ont été utilisées pour le construire. Une fois construite, la plage est fixed .
Il considère range(..)
comme un objet iterable , et chaque itération prend l'élément suivant que l'itérable donne. Ainsi, que vous définissiez la variable ou non dans la boucle for
, il y a no effect pour la prochaine itération.
Dans python-2.x , range(..)
n'est pas un objet spécifique, mais un appel pour construire une liste. Donc, si vous appelez range(10)
(sans la boucle for
), vous obtenez [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
.
Alors, pourquoi les exemples ne fonctionnent-ils pas?
a=5
for i in range(1,a):
print(i)
a=a+1
Ici, nous construisons range(..)
une fois. Après cela, les variables sur lesquelles il a été construit peuvent changer, car l'objet range(..)
ne change plus. Incrémenter a
ne signifiera donc pas que l’objet range
deviendra plus grand.
for i in range(1,4):
print(i)
i=i-1
La boucle for
prend à chaque fois l'élément next de l'itérable. Donc, si nous avons d'abord collecté 1
à partir de la boucle range
, à la prochaine itération, nous collectons 2
. Quelle que soit la valeur de i
.
for i in range(1,4):
print(i)
i=1
Pour la même raison: for
fait not prend en compte la valeur précédente de i
. Il ne récupère que l'élément suivant l'itérable (ici, range(..)
donne). Puisque range(..)
est corrigé, il ne fera que nourrir la boucle for
à l'élément suivant.
Nous avons donc besoin de construire un itérable qui continue à produire des éléments. Une façon de faire est itertools.count
:
from itertools import count
for i in count():
# ...
pass
Ou si vous n'êtes intéressé par aucune valeur, nous pouvons également utiliser repeat
:
from itertools import repeat
for _ in repeat(None):
# ...
pass
Parce qu'une plage est une liste (Python2) ou un objet range
qui sont tous deux finis. Cette plage est créée une fois avant le début de la boucle. L'élément suivant de la plage, au début de chaque itération, est affecté à votre variable de boucle, quelle que soit l'affectation que vous lui attribuez ultérieurement dans le corps de la boucle. Vous avez besoin d'un itérateur infini pour une boucle infinie, par exemple. itertools.cycle
:
from itertools import cycle
for x in cycle(range(5)):
# endless
range
copie les paramètres qui lui sont attribués pour un usage interne. Donc, les changements apportés à ceux qui suivent n'ont aucun effet. Identique à la variable de boucle, qui est uniquement créée à partir des valeurs internes à chaque fois.
En revanche, si vous utilisez un objet mutable tel que list
pour le parcourir:
a = [1,2,3]
for i in a:
a.append(i)
Cette boucle fonctionnera effectivement à l'infini.