Pythonのwhile文を使って無限ループを記述する方法やその際の注意点、for文と無限イテレータを使って無限ループを記述する方法を紹介する。
この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。
* 本稿は2021年10月19日に公開された記事をPython 3.12.0で動作確認したものです(確認日:2023年12月1日)。
# 処理を5回行うまではループを続ける
cnt = 0
while True:
print(cnt) # 何らかの処理
cnt += 1
if cnt >= 5:
break
# 無限ループでキューから値を取り出す
import time
from queue import Queue
from threading import Thread
def do_in_thread(q):
while True:
item = q.get(block=True)
if not item: # 取り出した要素が偽と見なされる値(空文字列など)であれば
break # 無限ループを終了
print(item)
print('out while loop')
# 以下の書き方も考えられる
#def do_in_thread(q):
# item = q.get(block=True)
# while item:
# print(item)
# item = q.get(block=True)
# print('out while loop')
q = Queue()
th = Thread(target=do_in_thread, args=[q])
th.start()
for item in ['foo', 'bar', 'baz', '', 'hoge']:
time.sleep(2)
q.put(item)
# for文を使った無限ループ
from itertools import count, cycle, repeat
for num in count():
print(num)
if num >= 4:
break
for idx, item in enumerate(cycle(['foo', 'bar', 'baz'])):
print(item)
if idx >= 4:
break
for item in repeat('foo', 4):
print(item)
while文は何らかの条件が成立している間、特定の処理を実行し続ける。「条件が成立」するとは、その式の評価結果が真(True)となることだ。そのため、条件にTrueを指定すると、while文の本体が無限に実行されることになる。このため、Pythonでは「while True:」で始まるwhile文を「無限ループ」と呼ぶことがよくある。
while True: # 条件がTrue、つまり常に成立するので
pass # この行を無限に実行し続ける
無限ループは本当に無限にループを実行するのが目的ではなく、ループの中で特定の条件が成立したら、ループを終了させるようなコードを書く。以下は変数cntの値が5以上になったらループを終了する無限ループだ。
cnt = 0
while True:
print(cnt) # 何らかの処理
cnt += 1
if cnt >= 5:
break
上で見たように、while文の条件にTrueを指定して、その内部で何らかの処理を行った上で、ループを終わらせるかどうかの判定を行い、条件が成り立てばbreak文でループを終了させるのが無限ループの基本的な構造となる。無論、while文の条件にそうした記述が可能であれば、そうするのがよいだろう。上の無限ループは下のように書き直せる。
cnt = 0
while cnt < 5:
print(cnt)
cnt += 1
また、条件にはTrueを指定せずとも、PythonでTrueと見なされる値を指定してもよい。例えば、以下のコードはメインスレッドでは2秒おきにキューに要素を追加して、もう1つのスレッドでは、キューから変数itemに要素を取り出し、その値を画面に出力するという処理を「while True:」で始まる無限ループの形で行っている(終了条件は変数itemに取り出した値が空文字列であること)。
import time
from queue import Queue
from threading import Thread
def do_in_thread(q: Queue):
while True:
item = q.get(block=True)
if not item: # 取り出した要素が偽と見なされる値(空文字列など)であれば
break # 無限ループを終了
print(item)
print('out while loop')
q = Queue()
th = Thread(target=do_in_thread, args=[q])
th.start()
for item in ['foo', 'bar', 'baz', '', 'hoge']:
time.sleep(2)
q.put(item)
この例では、変数itemに取り出されるのは'foo'、'bar'、'baz'、''、'hoge'という文字列だ。Pythonでは空文字列(’’)は偽(False)として見なされるので、これをif文でチェックするようにしている。それ以外の文字列は全て真(True)となるので、上記のdo_in_thread関数は次のようにも書ける。
def do_in_thread(q: Queue):
item = q.get(block=True)
while item:
print(item)
item = q.get(block=True)
print('out while loop')
書き換えたコードでは「item = q.get(block=True)」行を2カ所に記述することになるが、if文での条件判断が不要になる。どちらが適切かの判断は難しいが、お好みの書き方をすればよいだろう。
注意点としては、「while True:」による無限ループは特に何もなければ、その本体に記述したコードを無限に実行し続けるという点だ。何をいっているんだと思うかもしれないが、以下のコードを見てほしい(これは恣意(しい)的なコードである)。
from threading import Thread, Event
import time
def do_in_thread(ev):
cnt = 0
print('in thread')
while True:
print('in while loop')
if ev.is_set():
print(f'event fired: {cnt}')
ev.clear()
cnt += 1
if cnt > 2:
break
else:
time.sleep(1)
print('out infinite loop')
ev = Event()
th = Thread(target=do_in_thread, args=[ev])
th.start()
for num in range(3):
time.sleep(2)
ev.set()
これは上の例と同じくthreadingモジュールを使っている。メインスレッドでは、2秒に1回イベントを発生させる動作を3回行う。もう1つのスレッドでは、無限ループの形でイベントの発生をチェックして、イベントが発生したら「event fired: 0」などの出力を行う(イベントが発生していなければ、1秒スリープする)。
Copyright© Digital Advantage Corp. All Rights Reserved.