web-dev-qa-db-fra.com

Boucles infinies utilisant 'for' en Python

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.

5
Nischal

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.

5

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.

3
Ari Cooper-Davis

Prenons une boucle forname__:

for item in iterable:
    print(item)

L'idée est que tant que iterablereste inchangé, nous allons parcourir chacun des itemdans iterableune 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.


Exemple 1

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.

Exemple 2

for i in range(1,4):
  print(i)
  i=i-1

Dans ce cas, iest réévalué chaque boucle avant d'exécuter les instructions printet i=i-1 dans le corps de la boucle.

Exemple 3

for i in range(1,4):
  print(i)
  i=1

Tout comme Exemple 2 , iest réévalué à chaque boucle.

3
Mateen Ulhaq

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].

Pourquoi ça ne marche pas?

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.

Emuler une boucle infinie

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
1
Willem Van Onsem

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
1
schwobaseggl

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.

1
Jeronimo