2016-04-09 14 views
1

は不自然な例です:forループの本体でイテレータ変数を再定義することはできますか?ここ

from itertools import cycle 
def foobar(): 
    A = [1,2,3,4,5] 
    B = [6,7,8,9,10] 
    it = cycle(A) 
    tmp=0 
    for item in it: 
     print item, tmp 
     if tmp>10: 
      it=cycle(B) #is this possible? 
     if tmp>30: 
      return tmp 
     tmp+=item 

は出力:

1 0 
2 1 
3 3 
4 6 
5 10 
1 15 
2 16 
3 18 
4 21 
5 25 
1 30 
2 31 

私はそれが私はを再定義し、その時点で、条件が満たされるまでループのために1つのiterableを反復しようとしていますそのため、同じループ本体を使用して別のリストを反復処理します。

コードは、私は現在の形でそれを希望方法は機能しない:それはサイクル(A)を使用し続け、私はそれ=サイクル(B)を再定義した後でも。私は、ループ内のコードがループ条件を変更できないスコープの問題があると考えています。私がここでやろうとしていることを達成する方法はありますか、複数のリストを繰り返し処理するために重複またはネストされたfor-loopsを作成する必要がありますか?

答えて

0

を私はそれがforループの条件を変更することはできないと思います。あなたはいつも、たとえば、あなたが使用したいイテレータの次の項目を変更しながら、いくつかのステートメントを使用することができます

from itertools import cycle 

def foobar(): 
    A = [1, 2, 3, 4, 5] 
    B = [6, 7, 8, 9, 10] 
    tmp = 0 
    iter_A = cycle(A) 
    iter_B = cycle(B) 
    use_A = True 
    while True: 
     if use_A: 
      item = next(iter_A) 
     else: 
      item = next(iter_B) 
     print item, tmp 
     if tmp > 10: 
      use_A = False 
     if tmp > 30: 
      return tmp 

     tmp += item 

出力:

1 0 
2 1 
3 3 
4 6 
5 10 
1 15 
6 16 
7 22 
8 29 
9 37 

私はこのことができます願っています。

更新:マルタインピータースからのコメントを1として

、次のようにも動作するはずです:非常に興味深いです

from itertools import cycle 

def foobar(): 
    A = [1, 2, 3, 4, 5] 
    B = [6, 7, 8, 9, 10] 
    tmp = 0 
    iter_A = cycle(A) 
    iter_B = cycle(B) 
    it = iter_A 
    while True: 
     item = next(it) 
     print item, tmp 
     if tmp > 10: 
      it = iter_B 
     if tmp > 30: 
      return tmp 

     tmp += item 
+1

フラグを使用するのではなく、単に 'it = iter_A'を使用し、その後' it = iter_B'に切り替えます。 –

1

あなたが望むものを直接行う方法はありません。コード内のforループは、最初に起動するときに渡すイテラブルの初期値のみを参照します。そのiterableでiter()を呼び出し、iteratorを使用してアイテムを繰り返し取得します。 forで使用した変数をリバックすると、ループの内部ロジックによってイテレータが使用されていないため、その変数は何も変更されません。

私はbreakを使用していると思われます。これを解決するには別のループが最適です。しかし、あなた本当には、現在、あなたがオンデマンドで別の(内部に格納されている)イテレータからスワップを聞かせ独自のイテレータを書くことができますどのように可能な限り近いループコードを維持したい場合:

class swapable_iterator(object): 
    def __init__(self, it): 
     self.it = it 

    def __iter__(self): 
     return self 

    def next(self): 
     return next(self.it) 

    __next__ = next # Python 3 compatibility 

    def swap(self, new_it): 
     self.it = new_it 

現在のところ、cycle(B)tmp > 10の後)にスワップされ、最初の値だけが表示されるため、ループロジックを少し変更する必要があります。

ような何か試してみてください:

def foobar(): 
    A = [1,2,3,4,5] 
    B = [6,7,8,9,10] 
    it = swapable_iterator(cycle(A)) # wrap the cycle with our custom iterator object 
    tmp=0 
    for item in it: 
     print item, tmp 
     if item == 5 and tmp > 10: # this will happen exactly once with the A and B above 
      it.swap(cycle(B)) # this modifies "it" in place, rather than rebinding it 
     if tmp>30: 
      return tmp 
     tmp+=item 
+0

を。スワップ可能なイテレーターは実際には動作しますか? forループが 'iter()'の結果を使用している場合、 'it.swap'を以前と同じ問題に遭遇すると思われます。つまり、forループが再実行されないということですイテレータを評価し、ループ条件を変更します。回答ありがとうございます – user309775

+0

イテレータなので、 '__iter__'メソッドは' self'を返します。その理由は、元のコード( 'サイクル 'は' __iter__'メソッドが 'self'を返すイテレータでもあったため)で' it'をリバインドしていたということでした。イテレータは適所にある。 'it.swap'(' it'が 'swapable_iterator'のとき)を呼び出すと、それを適所で修正するので、ループは必要に応じて変更を受け取ります。 – Blckknght

関連する問題