web-dev-qa-db-ja.com

Pythonで 'for'を使用した無限ループ

なぜこれは無限ループを作成しないのですか?

a=5
for i in range(1,a):
  print(i)
  a=a+1

またはこれ

for i in range(1,4):
  print(i)
  i=i-1

またはこれ

for i in range(1,4):
  print(i)
  i=1

forループを使用して無限ループを作成する方法はありますか?そのためのwhileループがあることは知っていますが、興味がありました。

5
Nischal

rangeクラス であり、たとえばrange(1, a)は、そのクラスのobjectを作成します。このオブジェクトは1回だけ作成され、ループの反復ごとに再作成されるわけではありません。これが、最初の例で無限ループが発生しない理由です。

他の2つのループは、rangeオブジェクトとは異なり、ループ変数i再作成される(またはむしろreinitialized)各反復。ループ内でiに割り当てた値は、ループが繰り返されるときに上書きされます。

forループを考えてみましょう。

_for item in iterable:
    print(item)
_

iterableが変更されていない限り、item内のすべてのiterableを1回ループするという考え方です。例えば、

_for item in [3, 2, 1, 666]:
    print(item)
_

_3 2 1 666_を出力します。特に、range(1, 4)は反復可能な_[1, 2, 3]_を表す簡単な方法であることがわかります。したがって、

_for i in range(1, 4):
    print(i)
_

_1 2 3_を出力します。


例1

_a=5
for i in range(1,a):
  print(i)
  a=a+1
_

この場合、ループの開始時にrange(1,a)が評価されますonce

例2

_for i in range(1,4):
  print(i)
  i=i-1
_

この場合、ループの本体内でiおよび_i=i-1_ステートメントを実行する前に、printがループごとに再評価されます。

例3

_for i in range(1,4):
  print(i)
  i=1
_

例2と同様に、iはループごとに再評価されます。

4
Mateen Ulhaq

この場合、forループがループしているイテレータを更新することはできません。


for i in range(a):rangeは実際には関数であり、値aを取り、ループする値を含むオブジェクトを返します。そのオブジェクトを作成したら、入力変数を好きなだけ変更でき、そのオブジェクトは変更されません。

リストを生成するmy_rangeという独自の同様の関数を作成した場合を想像してみてください(組み込みのrange関数はrangeを生成します)。

def my_range(end):
    my_list = []
    for i in range(end):
        my_list.append(i)
    return my_list

ここで、次のように新しい関数を使用する場合:

a = 4
for i in my_range(a):
    print(i)
    a += 1

ループしているリストはすでに作成されており、再作成されていないため、aを変更してループしているリストオブジェクトを更新できないことは明らかです。すべてのループ。


Pythonで無限ループを作ることはできますか?はい、ループしているオブジェクトに新しいエントリを追加するだけです。例:

my_list = [0]
for i in my_list:
    print(i)
    my_list.append(i+1)

ここで、ループしているオブジェクトを更新しています。

3

forループとrange(..)オブジェクト

for i in range(..): Python doesnotと書くと、これをfor(int i = 0; i < n; i++)のように変換します(Cプログラミング言語ファミリー)。

さらに、範囲オブジェクトは、forループの前に1回作成されます。 range(..)オブジェクトは、それを構築するためにどの変数が使用されたかを知りません。構築されると、範囲は固定になります。

range(..)iterableオブジェクトと見なし、反復ごとに、iterableが生成する次のアイテムを取得します。したがって、forループで変数を設定するかどうかに関係なく、次の反復ではnoの効果があります。

python-2.x では、range(..)は特定のオブジェクトではなく、リストを作成するための呼び出しです。したがって、range(10)forループなし)を呼び出すと、[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]が得られます。

なぜそれが機能しないのですか?

では、なぜ例が機能しないのでしょうか。

a=5
for i in range(1,a):
  print(i)
  a=a+1

ここでは、range(..)を1回作成します。その後、range(..)オブジェクトが変更されるため、作成元の変数が変更される可能性があります。したがって、aをインクリメントしても、rangeオブジェクトが大きくなるわけではありません。

for i in range(1,4):
  print(i)
  i=i-1

毎回forループは、反復可能オブジェクトのnext項目を取ります。したがって、最初にrangeループから1を収集した場合、次の反復では、2を収集します。これは、iの値が何であるかに関係ありません。

for i in range(1,4):
  print(i)
  i=1

まったく同じ理由で:fornotiの以前の値を考慮しません。反復可能な次のアイテムのみをフェッチします(ここではrange(..)が生成されます)。 range(..)は修正されているため、次のアイテムをforループにフィードするだけです。

無限ループのエミュレート

したがって、要素を生成し続ける反復可能オブジェクトを構築する必要があります。これを行う方法はitertools.countです:

from itertools import count

for i in count():
    # ...
    pass

または、値に関心がない場合は、repeatも使用できます。

from itertools import repeat

for _ in repeat(None):
    # ...
    pass
1

範囲はリスト(Python2)またはrangeオブジェクトのいずれかであり、どちらも有限であるためです。その範囲は、ループが開始する前に1回作成されます。ループ変数は、ループ本体の後半で何を割り当てるかに関係なく、各反復の開始時に範囲の次の要素に割り当てられます。無限forループには、無限イテレータが必要です。 itertools.cycle

from itertools import cycle
for x in cycle(range(5)):
    # endless
1
schwobaseggl

rangeは、内部で使用するために指定されたパラメーターをコピーします。したがって、後でそれらを変更しても効果はありません。毎回内部値からのみ作成されるループ変数と同じです。

ただし、listのような可変オブジェクトを使用して反復する場合は異なります。

a = [1,2,3]

for i in a:
    a.append(i)

このループは確かに無限に実行されます。

1
Jeronimo