4
votes

En Python, les conditions d'une boucle sont-elles réévaluées avant qu'une nouvelle itération ne soit exécutée?

En ce qui concerne python, quand il s'agit d'une boucle for, va-t-il réévaluer la limite supérieure avant la réitération?

Disons que j'ai le scénario suivant:

def remove(self,list,element):
     for x in range(0,len(list)):
           if somecondition:
               list.pop(x)


3 commentaires

Une vérification rapide suggère que len (some_list) ne sera pas réévalué si vous ajoutez pendant l'itération. OTOH, si vous bouclez sur la liste elle-même et ajoutez ( for x in some_list: ) alors l'itérateur devient confus. La mutation des collections tout en les itérant est généralement évitée en Python, à moins que vous ne sachiez ce que vous faites.


Quelle enquête avez-vous essayée - c'est assez facile à démontrer.


Vous devriez lire sur les générateurs en python. La boucle for est juste un wrapper pour try, iter = next (gen) do loop, catch. Cela permet une compréhension plus profonde


3 Réponses :


1
votes

Oui, vous pouvez voir une erreur hors limites si vous essayez ce qui suit:

my_list = [0,1,2,3,4,5]
for x in range(0, len(my_list)):
    print("Length of my_list:", len(my_list))
    my_list.pop(x)

(Vous devriez également éviter d'utiliser un nom de variable comme list car il suivra la list intégrée de Python.)


2 commentaires

Il s'agissait plus d'un exemple générique que d'un code réel.


À quoi dites-vous «oui»? La réponse à la question dans le titre est clairement "Non". Cela ne démontre pas que range () est réévalué à chaque itération - bien au contraire (car ce n'est pas le cas). Au lieu de cela, lorsque x devient 3, il ne reste plus que 3 éléments dans ma_liste donc le pop est hors de portée. L'itération est fixée à 6, l'itération se termine par l'erreur, non par la réévaluation de la longueur. Il faut éviter de répondre «oui» ou «non» - la question pourrait facilement être modifiée pour inverser le sens. Il est plus sûr de déclarer clairement ce que vous affirmez.



6
votes

La documentation sur La déclaration for est claire à propos de ceci:

L'instruction for est utilisée pour parcourir les éléments d'une séquence (comme une chaîne, un tuple ou une liste) ou autre objet itérable:

for_stmt :: = "pour" target_list "dans" expression_list ":" suite ["else" ":" suite]

La liste d'expressions est évaluée une fois ; il doit produire un objet itérable. Un itérateur est créé pour le résultat de l'expression_list. La suite est ensuite exécutée une fois pour chaque élément fourni par l'itérateur, dans l'ordre renvoyé par le itérateur.

[c'est moi qui souligne]

Donc, dans votre cas, range (0, len (list)) ne sera évalué qu'une seule fois.


2 commentaires

Je vois, ai-je raison de supposer que cela serait également vrai pour la plage (0, Y)? Étant donné que Y est modifié à l'intérieur de la boucle


Vous l'êtes, ce serait le cas pour n'importe quelle expression. L'objet range est créé une fois pour toutes, puis il sera itéré dessus.



0
votes

Considérez le code suivant:

0 4
1 4
2 4
3 4

Chaque fois que test () est appelé i est incrémenté, la boucle sera donc sans fin si code > test () `ont été évalués à chaque itération. Le résultat est cependant:

i = 3

def test():
  global i ;
  i = i + 1
  return i

for x in range(0,test()):
  print( x, i )

Il est donc clair que test () est évalué une fois.


0 commentaires