Heres the code python im ayant des problèmes avec:
for i in range (0,10):
if i==5:
i+=3
print i
Je m'attendais à ce que le résultat soit:
0
1
2
3
4
8
9
cependant l'interprète recrache:
0
1
2
3
4
8
6
7
8
9
Je sais qu'une boucle for
crée une nouvelle portée pour une variable en C, mais je n'ai aucune idée de python. Quelqu'un peut-il expliquer pourquoi la valeur de i
ne change pas dans la boucle for
en python et quelle est la solution pour obtenir le résultat attendu?.
La boucle for parcourt tous les nombres dans range(10)
, c'est-à-dire [0,1,2,3,4,5,6,7,8,9]
.
Le fait de changer la valeur current de i
n'a aucun effet sur la valeur suivante de la plage.
Vous pouvez obtenir le comportement souhaité avec une boucle while.
i = 0
while i < 10:
# do stuff and manipulate `i` as much as you like
if i==5:
i+=3
print i
# don't forget to increment `i` manually
i += 1
Vous imaginez que votre for-loop
en python ressemble à ce code C:
for (int i = 0; i < 10; i++)
if (i == 5)
i += 3;
Cela ressemble plus à ce code C:
int r[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
for (int j = 0; j < sizeof(r)/sizeof(r[0]); j++) {
int i = r[j];
if (i == 5)
i += 3;
}
Donc, modifier i
dans la boucle n'a pas l'effet escompté.
Vous pouvez regarder le désassemblage du code python pour voir ceci:
>>> from dis import dis
>>> def foo():
... for i in range (0,10):
... if i==5:
... i+=3
... print i
...
>>> dis(foo)
2 0 SETUP_LOOP 53 (to 56)
3 LOAD_GLOBAL 0 (range)
6 LOAD_CONST 1 (0)
9 LOAD_CONST 2 (10)
12 CALL_FUNCTION 2
15 GET_ITER
>> 16 FOR_ITER 36 (to 55)
19 STORE_FAST 0 (i)
3 22 LOAD_FAST 0 (i)
25 LOAD_CONST 3 (5)
28 COMPARE_OP 2 (==)
31 POP_JUMP_IF_FALSE 47
4 34 LOAD_FAST 0 (i)
37 LOAD_CONST 4 (3)
40 INPLACE_ADD
41 STORE_FAST 0 (i)
44 JUMP_FORWARD 0 (to 47)
5 >> 47 LOAD_FAST 0 (i)
50 PRINT_ITEM
51 PRINT_NEWLINE
52 JUMP_ABSOLUTE 16
>> 55 POP_BLOCK
>> 56 LOAD_CONST 0 (None)
59 RETURN_VALUE
>>>
Cette partie crée une plage comprise entre 0 et 10 et la réalise:
3 LOAD_GLOBAL 0 (range)
6 LOAD_CONST 1 (0)
9 LOAD_CONST 2 (10)
12 CALL_FUNCTION 2
À ce stade, le haut de la pile contient la plage.
Ceci obtient un itérateur sur l’objet au sommet de la pile , c’est-à-dire la plage:
15 GET_ITER
À ce stade, le haut de la pile contient un itérateur sur la plage réalisée.
FOR_ITER commence à parcourir la boucle en utilisant l'itérateur en haut de la pile:
>> 16 FOR_ITER 36 (to 55)
À ce stade, le haut de la pile contient la valeur suivante de l'itérateur.
Et ici vous pouvez voir que le haut de la pile est sauté et assigné à i
:
19 STORE_FAST 0 (i)
Donc i
sera écrasé indépendamment de ce que vous ferez dans la boucle.
Voici un aperçu des machines de la pile si vous ne l'avez pas déjà vu auparavant.
Une boucle for en Python est en fait une boucle for-each. Au début de chaque boucle, i
est défini sur l'élément suivant de l'itérateur (range(0, 10)
dans votre cas). La valeur de i
est réinitialisée au début de chaque boucle. Par conséquent, sa modification dans le corps de la boucle ne modifie pas sa valeur pour la prochaine itération.
Autrement dit, la boucle for
que vous avez écrite est équivalente à la boucle while suivante:
_numbers = range(0, 10) #the list [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
_iter = iter(_numbers)
while True:
try:
i = _iter.next()
except StopIteration:
break
#--YOUR CODE HERE:--
if i==5:
i+=3
print i
Si pour une raison quelconque vous vouliez vraiment modifier ajouter 3 à i
quand il est égal à 5
, et ignorer les éléments suivants (c'est un peu comme faire avancer le pointeur dans les éléments C 3), alors vous pouvez utiliser un itérateur et consommer quelques bits à partir de ce:
from collections import deque
from itertools import islice
x = iter(range(10)) # create iterator over list, so we can skip unnecessary bits
for i in x:
if i == 5:
deque(islice(x, 3), 0) # "swallow up" next 3 items
i += 3 # modify current i to be 8
print i
0
1
2
3
4
8
9
Dans python 2.7, la fonction range crée une liste, tandis que dans les versions 3.x de python, elle crée un objet de classe 'range' qui est seulement itérable, pas une liste, similaire à xrange dans python 2.7.
Pas lorsque vous parcourez la plage (1, 10), vous lisez éventuellement à partir de l'objet de type liste et i prend une nouvelle valeur chaque fois qu'il atteint la boucle.
c'est quelque chose comme:
for i in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]:
if i==5:
i+=3
print(i)
Changer la valeur ne changera pas l'ordre des itérations dans la liste.
it = iter(xrange (0,10))
for i in it:
if i==4: all(it.next() for a in xrange(3))
print i
ou
it = iter(xrange (0,10))
itn = it.next
for i in it:
if i==4: all(itn() for a in xrange(3))
print i
Je suis réinitialisé à chaque itération, donc peu importe ce que vous faites dans la boucle. La seule fois où il fait quoi que ce soit, c'est quand i est 5, et il ajoute 3 à cela. Une fois qu'il reboucle, il revient ensuite au numéro suivant de la liste. Vous voudrez probablement utiliser une while
ici.
La boucle for
de Python parcourt simplement la séquence de valeurs fournie - pensez-la comme "foreach". Pour cette raison, la modification de la variable n'a aucun effet sur l'exécution de la boucle.
Ceci est bien décrit dans le tutoriel .
Vous pouvez apporter les modifications suivantes à votre boucle for
:
for i in range (0,10):
if i in [5, 6, 7]:
continue
print(i)
À mon avis, le code analogue n'est pas une boucle while, mais une boucle for dans laquelle vous modifiez la liste pendant l'exécution:
originalLoopRange = 5
loopList = list(range(originalLoopRange))
timesThroughLoop = 0
for loopIndex in loopList:
print(timesThroughLoop, "count")
if loopIndex == 2:
loopList.pop(3)
print(loopList)
print(loopIndex)
timesThroughLoop += 1