C言語とかはfor(;;)
とかで無限ループできるらしいですが、pythonのfor文でも出来ます。気をつけて下さい。動作確認はpython3でやってますが、python2とかでも起きるはずです。
あと、普通に無限ループしたい場合はwhile True:
を使ってください。
方法
for文が参照しているリストをループ内で増やす。
サンプルコード
from time import pause # これなしで無限ループを試す度胸ないです
# 参照するリストの初期化
loop = [0]
# 無限ループ
for i in loop:
print(i)
pause(0.5)
loop.append(i+1)
適当なあたりで切り上げて下さい。
対策
ただループするつもりが、無限ループになっちゃった!というのはとても怖いので、対策をお伝えしておきます。
リストをコピーした上でfor文に渡して下さい。
# 有限ループ
for i in loop[:]:
print(i)
pause(0.5)
loop.append(i+1)
注意:対策になってそうでなってない奴
loop2 = loop
# 無限ループ
for i in loop2:
print(i)
pause(0.5)
loop.append(i+1)
これ、一旦loop2
にコピーしているので問題なさそうに見えますが、loop
に要素を追加すると、loop2
にも追加されます。
代入はオブジェクトをコピーせず、オブジェクトを共有します。
下のは問題ありません。[:]
をつけるとシャローコピーしてくれるので。
loop2 = loop[:]
# 有限ループ
for i in loop2:
print(i)
pause(0.5)
loop.append(i+1)
リストのコピーについて
コメントを受けて調べ直したところ、[:]
はシャローコピーとは違うことがわかりました。
4種類のリストのコピーとその違いを紹介します。
before = [[1,2,3], [4,5,6]]
以下の四つです。
- そのまま代入
- スライス(
[:]
)を使う -
list()
を使う -
copy.deepcopy
を使う
そのまま代入
after_eq = before
ここで、after_eq
とbefore
のid
を調べてみましょう
id(after_eq) == id(before)
# => True
これはどういうことかというと、リストはコピーされず、ひとつのリストを二つの変数から扱える状態です。
それが嬉しいかはわかりません。
スライス([:]
)やlist()
を使う
この二つは結果が同じです。
after_sl = before[:]
id(after_sl) == id(before)
# => False
after_ls = list(before)
id(after_sl) == id(before)
# => False
このように、スライスやlist()
を使うと全く別のリストがコピー出来たように思います。しかし、
id(after_sl[0]) == id(before[0])
# => True
id(after_ls[0]) == id(before[0])
# => True
となります。つまり、一階層だけコピーするシャローコピーと言うことです。
これがどういう意味かは、以下の例も参考にして考えてみて下さい。
zero = [[0]]
zeros = zero*3
print(zeros)
# => [[0], [0], [0]]
zeros[0][0] = '0'
print(zeros)
# =>[['0'], ['0'], ['0']]
copy.deepcopy
を使う
1番安全なのは、標準ライブラリ内のcopy.deepcopy
を使うことだと思います。
import copy
after_dc = copy.deepcopy(before)
id(after_dc) == id(before)
# => False
id(after_dc[0]) == id(before[0])
# => False
これこそがディープコピーというものです。