はじめに
今回はいろいろな方法で無限ループさせて遊んでみました。本題に入る前に、いわゆる普通の無限ループを置いておきます。これ以降一切while
を使いません。
while True:
print("This is an infinite loop")
このようにThis is an infinite loop
を無限に表示するのが目的です。厳密には無限でないものもありますが、回数を指定せずに限界まで勝手に表示し続けるものは、仲間に入れてあげたいと思います。
itertools.cycle
import itertools
for _ in itertools.cycle([None]):
print("This is an infinite loop")
エントリーナンバー1のitertools.cycle
です。通常の使い方は、リストを渡して、その要素を順番に取り出してもらう事です。今回は取り出したものは無視して、ただ無限ループを作るのに使いました。
class MyIterator:
def __init__(self, arr):
self.arr = arr
self.current = 0
def __iter__(self):
return self
def __next__(self):
if self.current >= len(self.arr):
self.current = 0
item = self.arr[self.current]
self.current += 1
return item
def my_cycle(arr):
for i in MyIterator(arr):
yield i
for _ in my_cycle([None]):
print("This is an infinite loop")
自作するとこんな感じですね。
itertools.repeat
import itertools
for _ in itertools.repeat(None):
print("This is an infinite loop")
エントリーナンバー2のitertools.repeat
です。こちらは一つ渡してあげると、それを繰り返し返してくれるものです。例によって帰ってくるものは無視して、ただ無限ループを回すために使っています。
class MyIterator2:
def __init__(self, value):
self.value = value
def __iter__(self):
return self
def __next__(self):
return self.value
def my_repeat(value):
for i in MyIterator2(value):
yield i
for _ in my_repeat(None):
print("This is an infinite loop")
自作するとこんな感じですね。
itertools.count
import itertools
for _ in itertools.count():
print("This is an infinite loop")
エントリーナンバー3のitertools.count
です。こちらは数字を渡すと、その数字からカウントアップしてくれるものです。しつこいですが、今回はループを回すためだけに使っています。
class MyIterator3:
def __init__(self, value = None):
self.value = 0 if value is None else value
def __iter__(self):
return self
def __next__(self):
value = self.value
self.value += 1
return value
def my_count():
for i in MyIterator3():
yield i
for _ in my_count():
print("This is an infinite loop")
イテレーター(最小限)
class MyIterator4:
def __iter__(self):
return self
def __next__(self):
return None
for _ in MyIterator4():
print("This is an infinite loop")
エントリーナンバー4のイテレーター(最小限)です。先ほどまでの流れで、察しの良い方は気づいたと思います。無限ループを作るだけなら、何の処理もせずNone
を返しとけばいいですし、引数もいらないですよね。
append
arr = [None]
for i in arr:
print("This is an infinite loop")
arr.append(i)
エントリーナンバー5のappend
です。for i in
でarr
から取り出しつつ、arr
にappend
することで、無限ループさせています。どんどん配列が長くなっていくので、厳密にはメモリの限界が来たら終わりますが。記事の趣旨にはあってると思うので紹介しています。
再帰呼び出し
def loop():
print("This is an infinite loop")
loop()
loop()
エントリーナンバー6の再帰呼び出しです。これも再帰呼び出しの深さに上限が設けられてるので、厳密には無限じゃないですね。ですが、普通にプログラムを書いていても、終了条件のミスで遭遇しますので、仲間に入れてあげました。
デストラクタ
class Loop:
def __init__(self):
print("This is an infinite loop")
def __del__(self):
Loop()
Loop()
エントリーナンバー7のデストラクタです。デストラクタっていうのは、コンストラクタの反対で、インスタンスが破棄されるときに呼び出されるやつです。デストラクタの中で、新しくインスタンスを作ることで、無限ループを実装しています。敵を一体倒すと新しい敵が出てくるみたいな時には、実用できるかもしれません。ただし、終了条件をミスるとctrl + C
でも止まらない、ガチの無限ループに陥るので危険です。
相互import
import sys, importlib, test3
sys.setrecursionlimit(5000)
print("This is an infinite loop")
del sys.modules['test3']
import test3
importlib.reload(test3)
import sys, importlib, test2
del sys.modules['test2']
import test2
importlib.reload(test2)
エントリーナンバー8の相互import
です。こんなものは前代未聞なんじゃないでしょうか。ただお互いにimport
するだけだと、2,3回しか出力されなかったので、import
してある情報を消して、なかったことにしてから再度import
して、その上で再読み込みするというのをお互いにやっています。再帰呼び出しの一種っぽいので、これも厳密には無限ではなかったです。というか150回くらいしか出力されずに、上限に達してしまうので、再帰呼び出しの上限を5000回に増やす悪あがきをしています。
最後に
ここまで読んで下さりありがとうございました。一応何か一言残すなら、イテレーターと再帰呼び出しを使うときは、終了条件に気を付けよう!といったところでしょうか。他に面白いものを見つけたら追記するかもしれません。