web-dev-qa-db-ja.com

forループのpython変数の範囲

Heres pythonコードimに問題がある:

for i in range (0,10):
    if i==5:
        i+=3
    print i

出力は次のようになります。

0
1
2
3
4
8
9

ただし、インタープリターは吐き出します。

0
1
2
3
4
8
6
7
8
9

forループがCの変数の新しいスコープを作成することは知っていますが、Pythonについてはわかりません。 python)のiループでforの値が変化しない理由と、予想される出力を得るための対策を説明できる人はいますか。

32
firecast

Forループは、range(10)のすべての数値、つまり[0,1,2,3,4,5,6,7,8,9]
icurrent値を変更しても、範囲内の次の値には影響しません。

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
33
Junuxx

Cコードとの類推

あなたはあなたのfor-loop in 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 code の逆アセンブリを見ると、これを確認できます。

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

この部分 〜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はループの反復を開始します estackの先頭にある反復子を使用します。

    >>   16 FOR_ITER                36 (to 55)

この時点で、スタックの最上部にはイテレーターの次の値が含まれています。

そして、ここで スタックのトップがポップされ、i に割り当てられていることがわかります。

         19 STORE_FAST               0 (i)

したがって、iは、ループで何をするかに関係なく上書きされます。

スタックマシンの概要 は、これを見たことがない場合です。

18
hughdbrown

Pythonのforループは、実際にはfor-eachループです。各ループの開始時に、iが反復子の次の要素に設定されます(range(0, 10)あなたの場合)。iの値は各ループの開始時に再設定されるため、ループ本体で値を変更しても、次の反復の値は変更されません。

つまり、作成したforループは、次のwhileループと同等です。

_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
14
Claudiu

何らかの理由で本当に5に等しいときにiに3を追加し、次の要素をスキップしたい場合(これはC 3要素のポインタを進めるようなものです)、イテレータを使用して、そこから数ビットを消費できます。

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
4
Jon Clements
it = iter(xrange (0,10))
for i in it:
    if i==4: all(it.next() for a in xrange(3))
    print i

または

it = iter(xrange (0,10))
itn = it.next
for i in it:
    if i==4: all(itn() for a in xrange(3))
    print i
1
eyquem

繰り返しごとにリセットされるので、ループ内で何をするかは重要ではありません。何かをするのは、iが5のときだけで、その後3を追加します。ループバックすると、リスト内の次の番号にiが設定されます。おそらくここでwhileを使用したいでしょう。

1
Hoopdady

Pythonのforループは、指定された値のシーケンスを単純にループします。これを「foreach」と考えてください。このため、変数を変更してもループの実行には影響しません。

これは チュートリアル で詳しく説明されています。

1
user4815162342

python 2.7範囲関数はリストを作成しますが、python 3.xバージョンでは、リストではなく反復可能な 'range'クラスオブジェクトを作成します。 xrange in python 2.7。

Range(1、10)を繰り返し処理しているときではなく、最終的にはリスト型オブジェクトから読み取りを行い、forループに達するたびに新しい値を取得します。

これは次のようなものです:

for i in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]:
    if i==5:
        i+=3
    print(i)

値を変更しても、リストの反復順序は変更されません。

1
pranav dua

forループに次の変更を加えることができます。

for i in range (0,10):
    if i in [5, 6, 7]:
        continue
    print(i)
0
CopyPasteIt

私の見解では、類似したコードはwhileループではなく、実行時にリストを編集するforループです。

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
0
AdityaS