再帰処理
前回は、Pythonで再帰処理を使って0を含まないランダムな数値のリストを作成する方法を紹介しました。
今回は再帰処理を大量に行った場合に出る「RecursionError: maximum recursion depth exceeded while calling a Python object」の対処法を紹介します。
前回、再帰処理を使って0を含まないランダムな数値のリストを作成していて、どんどん取得する数値を増やしていったところ、「RecursionError: maximum recursion depth exceeded while calling a Python object」というエラーが出て、なんだろうとなったことが今回のお話の発端。
ということでそれを再現しつつ、解説をしていきましょう。
それでは始めていきましょう。
「RecursionError: maximum recursion depth exceeded while calling a Python object」の再現
まずは「RecursionError: maximum recursion depth exceeded while calling a Python object」のエラーを再現します。
前回のプログラムはこんな感じでした。
import random
x = []
def non_zero_random(n):
if n == 0:
return
val = random.randrange(10)
if val == 0:
non_zero_random(n)
else:
x.append(val)
non_zero_random(n-1)
non_zero_random(10)
print(x)
実行結果
[6, 4, 2, 2, 6, 5, 9, 6, 6, 7]
この「non_zero_random(n)」のnの数を100、1000、10000と変えていきました。
import random
x = []
def non_zero_random(n):
if n == 0:
return
val = random.randrange(10)
if val == 0:
non_zero_random(n)
else:
x.append(val)
non_zero_random(n-1)
non_zero_random(100)
print(x)
実行結果
[5, 6, 1, 5, 6, (中略) 2, 3, 5, 7, 4]
100個は問題なく処理できました。
import random
x = []
def non_zero_random(n):
if n == 0:
return
val = random.randrange(10)
if val == 0:
non_zero_random(n)
else:
x.append(val)
non_zero_random(n-1)
non_zero_random(1000)
print(x)
実行結果
[5, 4, 7, 7, 4, (中略) 7, 9, 1, 7, 9]
1000個も大丈夫です。
import random
x = []
def non_zero_random(n):
if n == 0:
return
val = random.randrange(10)
if val == 0:
non_zero_random(n)
else:
x.append(val)
non_zero_random(n-1)
non_zero_random(10000)
print(x)
実行結果
---------------------------------------------------------------------------
RecursionError Traceback (most recent call last)
Cell In[11], line 16
13 x.append(val)
14 non_zero_random(n-1)
---> 16 non_zero_random(10000)
18 print(x)
File /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/random.py:245, in Random._randbelow_with_getrandbits(self, n)
243 return 0
244 getrandbits = self.getrandbits
--> 245 k = n.bit_length() # don't use (n-1) here because n can be 1
246 r = getrandbits(k) # 0 <= r < 2**k
247 while r >= n:
RecursionError: maximum recursion depth exceeded while calling a Python object
10000個とした時に「RecursionError: maximum recursion depth exceeded while calling a Python object」が出ました。
このエラーはいわゆる再帰しすぎ、つまり再帰回数が内部で決まっており、その回数を超えましたというエラーです。
デフォルトの再帰回数を取得
再起回数の上限がいくつか確認してみましょう。
その場合は「sysモジュール」をインポートし、「sys.getrecursionlimit()」で取得できます。
import sys
sys.getrecursionlimit()
実行結果
3000
私の環境では「3000」と出たので、3000回までは再帰処理ができるようです。
とりあえず3001でエラーが出るか試してみます。
import random
x = []
def non_zero_random(n):
if n == 0:
return
val = random.randrange(10)
if val == 0:
non_zero_random(n)
else:
x.append(val)
non_zero_random(n-1)
non_zero_random(3001)
print(x)
実行結果
---------------------------------------------------------------------------
RecursionError Traceback (most recent call last)
Cell In[14], line 16
13 x.append(val)
14 non_zero_random(n-1)
---> 16 non_zero_random(3001)
18 print(x)
(中略)
File /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/random.py:245, in Random._randbelow_with_getrandbits(self, n)
243 return 0
244 getrandbits = self.getrandbits
--> 245 k = n.bit_length() # don't use (n-1) here because n can be 1
246 r = getrandbits(k) # 0 <= r < 2**k
247 while r >= n:
RecursionError: maximum recursion depth exceeded while calling a Python object
ちなみに今回のプログラムは処理回数を減らさずに再帰している場合もあるので「non_zero_random(3000)」としても、「RecursionError: maximum recursion depth exceeded while calling a Python object」のエラーが出ることがあります。
再帰処理の上限数を変更する方法
ただし設定されている上限よりも再帰処理を行いこともあることでしょう。
その際は「sysモジュール」をインポートし、「sys.setrecursionlimit(再帰処理の回数)」とすると再帰処理の上限数を変えることができます。
今回は再帰処理の上限を「5000」として、先ほどの「non_zero_random(3001)」としたプログラムが処理されるか試してみましょう。
import sys
sys.setrecursionlimit(5000)
sys.getrecursionlimit()
実行結果
5000
import random
x = []
def non_zero_random(n):
if n == 0:
return
val = random.randrange(10)
if val == 0:
non_zero_random(n)
else:
x.append(val)
non_zero_random(n-1)
non_zero_random(3001)
print(x)
実行結果
[3, 1, 5, 2, 2, (中略) 4, 8, 4, 8, 6]
上限が変更されたことが確認でき、ちゃんと3001回(それ以上)の再帰処理がされました。
次回はnumpyを使ってランダムな値を取得する方法を紹介します。
ではでは今回はこんな感じで。
コメント