Whileを使わずに無限ループさせて遊びたい！

## はじめに
　今回はいろいろな方法で無限ループさせて遊んでみました。本題に入る前に、いわゆる普通の無限ループを置いておきます。これ以降一切`while`を使いません。
```python
while True:
    print("This is an infinite loop")
```
このように`This is an infinite loop`を無限に表示するのが目的です。厳密には無限でないものもありますが、回数を指定せずに限界まで勝手に表示し続けるものは、仲間に入れてあげたいと思います。

## itertools.cycle
```python
import itertools
for _ in itertools.cycle([None]):
    print("This is an infinite loop")
```
エントリーナンバー１の`itertools.cycle`です。通常の使い方は、リストを渡して、その要素を順番に取り出してもらう事です。今回は取り出したものは無視して、ただ無限ループを作るのに使いました。

```python
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
```python
import itertools
for _ in itertools.repeat(None):
    print("This is an infinite loop")
```
エントリーナンバー２の`itertools.repeat`です。こちらは一つ渡してあげると、それを繰り返し返してくれるものです。例によって帰ってくるものは無視して、ただ無限ループを回すために使っています。
```python
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
```Python
import itertools
for _ in itertools.count():
    print("This is an infinite loop")
```
エントリーナンバー３の`itertools.count`です。こちらは数字を渡すと、その数字からカウントアップしてくれるものです。しつこいですが、今回はループを回すためだけに使っています。
```python
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")
```

## イテレーター（最小限）
```python
class MyIterator4:
    def __iter__(self):
        return self
    def __next__(self):
        return None
for _ in MyIterator4():
    print("This is an infinite loop")
```
エントリーナンバー４のイテレーター（最小限）です。先ほどまでの流れで、察しの良い方は気づいたと思います。無限ループを作るだけなら、何の処理もせず`None`を返しとけばいいですし、引数もいらないですよね。

## append
```python
arr = [None]
for i in arr:
    print("This is an infinite loop")
    arr.append(i)
```
エントリーナンバー５の`append`です。`for i in`で`arr`から取り出しつつ、`arr`に`append`することで、無限ループさせています。どんどん配列が長くなっていくので、厳密にはメモリの限界が来たら終わりますが。記事の趣旨にはあってると思うので紹介しています。

## 再帰呼び出し
```python
def loop():
    print("This is an infinite loop")
    loop()
loop()
```
エントリーナンバー６の再帰呼び出しです。これも再帰呼び出しの深さに上限が設けられてるので、厳密には無限じゃないですね。ですが、普通にプログラムを書いていても、終了条件のミスで遭遇しますので、仲間に入れてあげました。

## デストラクタ
```python
class Loop:
    def __init__(self):
        print("This is an infinite loop")
    def __del__(self):
        Loop()
Loop()
```
エントリーナンバー７のデストラクタです。デストラクタっていうのは、コンストラクタの反対で、インスタンスが破棄されるときに呼び出されるやつです。デストラクタの中で、新しくインスタンスを作ることで、無限ループを実装しています。敵を一体倒すと新しい敵が出てくるみたいな時には、実用できるかもしれません。ただし、終了条件をミスると`ctrl + C`でも止まらない、ガチの無限ループに陥るので危険です。

## 相互import
```python:test2.py
import sys, importlib, test3
sys.setrecursionlimit(5000)
print("This is an infinite loop")
del sys.modules['test3']
import test3
importlib.reload(test3)
```
```python:test3.py
import sys, importlib, test2
del sys.modules['test2']
import test2
importlib.reload(test2)
```
エントリーナンバー８の相互`import`です。こんなものは前代未聞なんじゃないでしょうか。ただお互いに`import`するだけだと、2,3回しか出力されなかったので、`import`してある情報を消して、なかったことにしてから再度`import`して、その上で再読み込みするというのをお互いにやっています。再帰呼び出しの一種っぽいので、これも厳密には無限ではなかったです。というか150回くらいしか出力されずに、上限に達してしまうので、再帰呼び出しの上限を5000回に増やす悪あがきをしています。

## 最後に
　ここまで読んで下さりありがとうございました。一応何か一言残すなら、イテレーターと再帰呼び出しを使うときは、終了条件に気を付けよう！といったところでしょうか。他に面白いものを見つけたら追記するかもしれません。