Cコードとの類推
あなたはあなたfor-loop
のPythonがこのCコードのようなものだと想像しています:
for (int i = 0; i < 10; i++)
if (i == 5)
i += 3;
これは、次の 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;
}
そのため、ループ内で変更i
しても、期待した効果は得られません。
分解例
Python コードの逆アセンブリを見ると、次のことがわかります。
>>> 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
>>>
この部分は、0 から 10 までの範囲を作成し、それを実現します。
3 LOAD_GLOBAL 0 (range)
6 LOAD_CONST 1 (0)
9 LOAD_CONST 2 (10)
12 CALL_FUNCTION 2
この時点で、スタックの一番上に範囲が含まれています。
これは、スタックの一番上にあるオブジェクト、つまり範囲の反復子を取得します。
15 GET_ITER
この時点で、スタックの一番上には、実現された範囲の反復子が含まれています。
FOR_ITER は、スタックの一番上にある反復子を使用して、ループの反復を開始します。
>> 16 FOR_ITER 36 (to 55)
この時点で、スタックの一番上には反復子の次の値が含まれています。
ここでは、スタックの一番上がポップされ、 に割り当てられてi
いることがわかります。
19 STORE_FAST 0 (i)
そのi
ため、ループで何をしても上書きされます。
これまでに見たことがない場合は、スタック マシンの概要を次に示します。