Code Fix

上級

再帰の終了条件が無いときの原因と直し方

再帰関数に終了条件(ベースケース)が無い、または正しく機能していないときに発生します。再帰は必ずどこかで止まる条件が必要です。

エラーメッセージの読み方

Traceback (most recent call last):
main.py
ファイル名
4
行番号 — 実際にクラッシュした行
countdown
発生場所 — <module> ならトップレベル、関数名ならその関数の中
RecursionError
例外クラス — 何が起きたか。ここを検索するのが最短です
maximum recursion depth exceeded
詳細メッセージ — どの値が問題だったか

このエラーが出る典型パターン

パターン1

 1  def countdown(n):
 2                      
                ^
 3      print(n)
 4      return countdown(n - 1)
 5  
 6  countdown(5)
Traceback (most recent call last): File "main.py", line 6, in <module> countdown(5) File "main.py", line 4, in countdown return countdown(n - 1) ^^^^^^^^^^^^^^^^ ...(同じ行が何度も繰り返される)... RecursionError: maximum recursion depth exceeded

終了条件(ベースケース)が無いと、再帰は自分自身を呼び続けます。Pythonは既定の再帰深度を超えると例外で止めます。

直し方: (空) を if n < 0: return にします。

この問題を解いてみる →

広告
広告スロット(未設定)

パターン2

 1  def factorial(n):
 2                         
                 ^
 3      return n * factorial(n - 1)
 4  
 5  print(factorial(5))
Traceback (most recent call last): File "main.py", line 5, in <module> print(factorial(5)) ^^^^^^^^^^^^ File "main.py", line 3, in factorial return n * factorial(n - 1) ^^^^^^^^^^^^^^^^ ...(同じ行が何度も繰り返される)... RecursionError: maximum recursion depth exceeded

階乗の計算は定番の再帰例ですが、n<=1で止める条件を書き忘れると永遠に自分自身を呼び続けます。

直し方: (空) を if n <= 1: return 1 にします。

この問題を解いてみる →

パターン3

 1  def sum_up_to(n):
 2                         
                 ^
 3      return n + sum_up_to(n - 1)
 4  
 5  print(sum_up_to(5))
Traceback (most recent call last): File "main.py", line 5, in <module> print(sum_up_to(5)) ^^^^^^^^^^^^^ File "main.py", line 3, in sum_up_to return n + sum_up_to(n - 1) ^^^^^^^^^^^^^^^^ ...(同じ行が何度も繰り返される)... RecursionError: maximum recursion depth exceeded

1からnまでの合計を再帰で求める場合も同様です。0以下になったら足すのをやめる条件が必要です。

直し方: (空) を if n <= 0: return 0 にします。

この問題を解いてみる →

パターン4

 1  def fibonacci(n):
 2                         
                 ^
 3      return fibonacci(n - 1) + fibonacci(n - 2)
 4  
 5  print(fibonacci(5))
Traceback (most recent call last): File "main.py", line 5, in <module> print(fibonacci(5)) ^^^^^^^^^^^^ File "main.py", line 3, in fibonacci return fibonacci(n - 1) + fibonacci(n - 2) ^^^^^^^^^^^^^^^^ ...(同じ行が何度も繰り返される)... RecursionError: maximum recursion depth exceeded

フィボナッチ数列の再帰でも同じです。小さいnで止める条件が無いと、マイナス方向にどこまでも呼び出しが続きます。

直し方: (空) を if n <= 1: return n にします。

この問題を解いてみる →

パターン5

 1  def power(base, exp):
 2                           
                  ^
 3      return base * power(base, exp - 1)
 4  
 5  print(power(2, 5))
Traceback (most recent call last): File "main.py", line 5, in <module> print(power(2, 5)) ^^^^^^^^^^^ File "main.py", line 3, in power return base * power(base, exp - 1) ^^^^^^^^^^^^^^^^^^^^ ...(同じ行が何度も繰り返される)... RecursionError: maximum recursion depth exceeded

べき乗の再帰計算も同じ構造です。指数が0になったら1を返して止める条件が必要です。

直し方: (空) を if exp <= 0: return 1 にします。

この問題を解いてみる →

よくある誤解

無限ループと違い、再帰の暴走はスタックが尽きるまで気づかれないことがあります。Pythonは既定で再帰の深さに上限を設けており、超えると例外で止めてくれます。

実務での勘所

デフォルトの再帰上限(sys.getrecursionlimit()で確認でき、既定は1000)は、理論的な限界ではなく、Pythonを実行しているCの呼び出しスタックが尽きてクラッシュする前に安全に止めるための人為的な安全マージンです。sys.setrecursionlimit()で上限を引き上げること自体は可能ですが、際限なく上げるとPythonの例外ではなくOSレベルのスタックオーバーフローでプロセスごと落ちる危険があります。また、Pythonは末尾再帰の最適化を行わない言語なので、深い再帰が本質的に必要な処理は、上限を上げるのではなくループに書き直すのが安全な解決策です。

演習をはじめる

関連するエラー

広告
広告スロット(未設定)