PythonのRecursionErrorとは?意味・原因・直し方を初心者向けに解説

ながみえ

Pythonで再帰処理を実行していると、次のようなエラーメッセージが表示されることがあります。

RecursionError: maximum recursion depth exceeded

RecursionErrorは、関数が自分自身を何度も呼び出し、再帰処理が深くなりすぎたときに発生するエラーです。

初心者のうちは、「終了条件を書いたはずなのに、なぜ処理が止まらないのだろう」と戸惑うこともあります。終了条件が書かれていても、その条件に到達しないコードになっていると、RecursionErrorは発生します。

この記事では、PythonのRecursionErrorが発生する原因、エラーになるコード、修正方法、再帰回数の確認方法をコード付きで分かりやすく解説します。

Pythonでよく出るエラーをまとめて確認したい方は、Pythonエラー一覧も参考にしてください。

あわせて読みたい
Pythonエラー一覧|よくあるエラーの意味・原因・直し方
Pythonエラー一覧|よくあるエラーの意味・原因・直し方
あわせて読みたい
Python入門講座|初心者向け無料カリキュラム
Python入門講座|初心者向け無料カリキュラム

PythonのRecursionErrorとは

RecursionErrorは、再帰による関数の呼び出しが深くなり、Pythonで設定されている上限を超えたときに発生するエラーです。

再帰とは、関数の中から同じ関数を呼び出す処理のことです。たとえば、count_down()という関数の中で、もう一度count_down()を実行する処理が再帰にあたります。

再帰処理では、前の関数が終了する前に、次の関数が呼び出されます。そのため、終了条件がなかったり、終了条件に到達できなかったりすると、関数の呼び出しが次々と積み重なっていきます。

maximum recursion depth exceededは、「再帰処理の深さが上限を超えました」という意味です。Pythonは処理が無限に続くことを防ぐため、関数を再帰的に呼び出せる深さに上限を設けています。

RecursionErrorが表示されたときは、上限を変更する前に、まず再帰処理を終了する条件と、関数に渡している値の変化を確認することが大切です。

RecursionErrorが起きる主な原因

RecursionErrorが発生する原因は、終了条件の書き忘れだけではありません。終了条件があっても、その条件に到達できなかったり、再帰処理の順番が間違っていたりすると、関数の呼び出しが止まらなくなります。

主な原因を整理すると、次のようになります。

原因内容確認すること
終了条件がない関数が自分自身を呼び続ける処理を終了するreturnがあるか
終了条件に到達しない引数が終了条件とは反対の方向へ変化している関数を呼び出すたびに値がどう変わるか
終了判定より先に再帰している条件を確認する前に、次の関数を呼び出している再帰呼び出しが終了条件より後にあるか
入力値が大きすぎる正しい再帰処理でも、呼び出し回数が多くなりすぎる入力値に対して何回の再帰が必要か
関数同士が呼び合っている複数の関数が互いを呼び出し続けている呼び出し先の関数から元の関数へ戻っていないか

初心者のうちは、終了条件が書かれているかだけを確認しがちです。しかし、実際には「その条件に本当に到達できるか」まで確認する必要があります。

たとえば、nが0になったら終了するコードでも、再帰するたびにn + 1としていると、値は0から遠ざかっていきます。この場合、終了条件は書かれていても処理は止まりません。

また、終了条件より前に再帰関数を呼び出している場合も、条件を確認する前に次の処理へ進んでしまいます。

RecursionErrorが出たときは、終了条件の有無だけでなく、引数の変化と再帰呼び出しの位置を順番に確認しましょう。

RecursionErrorのエラー例と修正例

RecursionErrorは、再帰処理の終了条件や、関数に渡す値の変化を確認すると原因を見つけやすくなります。

ここでは、初心者がつまずきやすい4つのパターンを、エラーになるコードと修正後のコードに分けて解説します。

終了条件が書かれていない

再帰関数には、処理を止めるための終了条件が必要です。終了条件がない場合、関数は自分自身を呼び出し続けます。

次のコードでは、count_down()の中から何度も同じ関数を呼び出しています。

def count_down(n):
    print(n)
    count_down(n - 1)

count_down(3)

実行すると、nの値を減らしながらcount_down()を呼び出し続けます。しかし、どの値になったら処理を終えるのかが書かれていません。

そのため、関数の呼び出しが積み重なり、最終的に次のようなエラーが発生します。

RecursionError: maximum recursion depth exceeded

修正するには、nが0以下になったときに処理を終了する条件を追加します。

def count_down(n):
    print(n)

    if n <= 0:
        return

    count_down(n - 1)

count_down(3)

このコードでは、nが0以下になるとreturnが実行されます。そこで関数が終了するため、それ以上count_down()は呼び出されません。

このような再帰処理を止める条件は、「終了条件」や「ベースケース」と呼ばれます。すべての用語を暗記する必要はありませんが、再帰関数には処理を止める条件が必要だと覚えておきましょう。

引数が終了条件に近づいていない

終了条件が書かれていても、引数がその条件に近づかなければ再帰処理は止まりません。

次のコードでは、nが0以下になったら終了するように書かれています。

def count_down(n):
    if n <= 0:
        return

    print(n)
    count_down(n + 1)

count_down(3)

一見すると終了条件があるため、問題がないように見えるかもしれません。しかし、再帰するたびにn + 1としているため、nの値は3、4、5と増えていきます。

終了条件はn <= 0ですが、値は0から遠ざかっています。そのため、条件に到達できず、RecursionErrorが発生します。

修正するには、再帰するたびにnが終了条件へ近づくようにします。

def count_down(n):
    if n <= 0:
        return

    print(n)
    count_down(n - 1)

count_down(3)

修正後は、nの値が3、2、1、0と減っていきます。0になると終了条件が成立し、再帰処理が止まります。

終了条件を確認するときは、条件が書かれているかだけでなく、関数を呼び出すたびに引数がその条件へ近づいているかも確認しましょう。

終了条件より先に再帰している

終了条件が正しく書かれていても、再帰関数を呼び出す位置によっては処理を止められません。

次のコードは、階乗を再帰処理で計算しようとした例です。

def factorial(n):
    next_value = factorial(n - 1)

    if n <= 1:
        return 1

    return n * next_value

print(factorial(5))

このコードには、nが1以下になったら終了する条件があります。しかし、その条件を確認する前にfactorial(n - 1)を実行しています。

そのため、nが1や0になっても、終了条件へ進む前に次のfactorial()が呼び出されます。結果として再帰処理が止まらず、RecursionErrorが発生します。

修正するには、再帰関数を呼び出す前に終了条件を確認します。

def factorial(n):
    if n <= 1:
        return 1

    next_value = factorial(n - 1)
    return n * next_value

print(factorial(5))

修正後は、nが1以下になると先にreturn 1が実行されます。そのため、そこから先の再帰呼び出しは行われません。

再帰関数では、基本的に終了条件を先に確認し、その後で次の再帰処理を実行すると考えると分かりやすいです。

再帰処理をfor文に書き換える

終了条件や引数の変化に問題がなくても、入力値が大きいと再帰処理が深くなりすぎる場合があります。

たとえば、次のコードでは再帰処理を使って階乗を計算しています。

def factorial(n):
    if n <= 1:
        return 1

    return n * factorial(n - 1)

print(factorial(5))

小さな値であれば正常に実行できます。しかし、nに非常に大きな値を渡すと、必要な再帰回数も多くなります。その結果、Pythonの再帰回数の上限を超える可能性があります。

このような単純な繰り返し処理は、for文に書き換えることができます。

def factorial(n):
    result = 1

    for number in range(2, n + 1):
        result *= number

    return result

print(factorial(5))

for文を使ったコードでは、関数が自分自身を呼び出しません。そのため、再帰処理の深さが上限を超える問題を避けられます。

すべての再帰処理をループに直す必要はありません。ただし、同じ計算を順番に繰り返すだけであれば、for文やwhile文を使ったほうが処理の流れを追いやすくなることがあります。

RecursionErrorが発生したときは、再帰回数の上限を変更する前に、ループへ書き換えられないかも検討しましょう。

Pythonの再帰回数の上限を確認・変更する方法

RecursionErrorが発生したときは、Pythonで設定されている再帰回数の上限を確認できます。また、必要に応じて上限を変更することも可能です。

ただし、上限を変更する前に、終了条件や引数の変化に間違いがないかを確認することが大切です。コードに問題がある状態で上限だけを増やしても、根本的な解決にはなりません。

現在の再帰回数の上限を確認する

Pythonでは、sys.getrecursionlimit()を使うと、現在設定されている再帰の上限を確認できます。

次のコードを実行してみましょう。

import sys

print(sys.getrecursionlimit())

実行環境によって異なる場合がありますが、次のように表示されることがあります。

1000

この値は、再帰関数を必ず1000回まで呼び出せるという意味ではありません。

sys.getrecursionlimit()で確認できるのは、Pythonのインタープリターが管理している呼び出しの深さの上限です。実際にRecursionErrorが発生するタイミングは、実行している処理や環境によって変わることがあります。

初心者のうちは、正確な回数を細かく意識するよりも、「関数の呼び出しが深くなりすぎるとRecursionErrorが発生する」と考えると分かりやすいです。

sys.setrecursionlimit()で上限を変更する

再帰処理が正しく書かれていても、扱うデータが大きい場合は上限を超えることがあります。その場合は、sys.setrecursionlimit()を使って上限を変更できます。

たとえば、上限を2000に変更する場合は、次のように書きます。

import sys

sys.setrecursionlimit(2000)

print(sys.getrecursionlimit())

実行すると、変更後の値が表示されます。

2000

sys.setrecursionlimit()の引数には、新しく設定したい上限値を指定します。

ただし、RecursionErrorが発生したからといって、すぐに大きな値へ変更するのはおすすめできません。終了条件がない再帰処理では、上限を増やしても関数の呼び出しが続くだけです。

また、必要以上に大きな値を設定すると、Pythonが異常終了する可能性があります。再帰の上限は、Pythonの処理を安全に動かすために設けられているためです。

上限を変更する前に、まずは次の点を確認しましょう。

  1. 再帰処理に終了条件が書かれているか
  2. 引数が終了条件へ近づいているか
  3. 終了条件より前に再帰関数を呼び出していないか
  4. for文やwhile文へ書き換えられないか
  5. 本当に深い再帰処理が必要か

コードに問題がなく、処理の性質上どうしても深い再帰が必要な場合に限り、上限の変更を検討します。

再帰回数の上限を増やしても解決しない場合

上限を増やしてもRecursionErrorが再び発生する場合は、再帰処理そのものに問題がある可能性が高いです。

たとえば、次のコードには終了条件がありません。

import sys

sys.setrecursionlimit(2000)

def repeat():
    repeat()

repeat()

上限を2000に増やしても、repeat()は自分自身を呼び出し続けます。そのため、最終的には再びRecursionErrorが発生します。

この場合、必要なのは上限の変更ではなく、処理を終了する条件を追加することです。

RecursionErrorが出たときは、sys.setrecursionlimit()を最初の解決方法にするのではなく、再帰処理の流れを見直すことを優先しましょう。

RecursionErrorが出たときの確認ポイント

RecursionErrorが発生したときは、再帰回数の上限を変更する前に、コードの流れを順番に確認しましょう。

特に、終了条件、引数の変化、再帰関数を呼び出す位置の3点を確認すると、原因を見つけやすくなります。

確認するポイントは、次のとおりです。

  1. エラーメッセージの最後にRecursionErrorと表示されているか
  2. 関数の中から同じ関数を呼び出しているか
  3. 再帰処理を終了する条件が書かれているか
  4. 終了条件が再帰呼び出しより前に書かれているか
  5. 引数が呼び出すたびに終了条件へ近づいているか
  6. 2つ以上の関数が互いに呼び出し続けていないか
  7. 入力値が大きすぎないか
  8. for文やwhile文に書き換えられないか
  9. sys.setrecursionlimit()を使う前にコードのミスを確認したか

まずは、エラーメッセージの最後の行を確認します。次のように表示されていれば、再帰処理の深さが上限を超えています。

RecursionError: maximum recursion depth exceeded

次に、関数の中で同じ関数を呼び出している場所を探します。

たとえば、次のコードではcount_down()の中から、もう一度count_down()を呼び出しています。

def count_down(n):
    count_down(n - 1)

再帰呼び出しを見つけたら、その前に終了条件があるかを確認します。

終了条件が書かれている場合でも、関数へ渡す値が条件に近づいているとは限りません。n <= 0で終了するなら、再帰するたびにnが小さくなっている必要があります。

また、複数の関数が互いを呼び出している場合は、コードを見ただけでは再帰処理に気づきにくいことがあります。

たとえば、次のようなコードです。

def function_a():
    function_b()

def function_b():
    function_a()

function_a()

function_a()function_b()を呼び出し、function_b()は再びfunction_a()を呼び出しています。このように、別の関数を経由して元の関数へ戻る処理も再帰の一種です。

原因が分からないときは、関数の先頭で引数を表示する方法もあります。

def count_down(n):
    print("現在のn:", n)

    if n <= 0:
        return

    count_down(n - 1)

count_down(3)

引数を表示すると、値が終了条件へ近づいているかを確認できます。

ただし、終了しない再帰処理で大量の値を表示すると、出力が長くなることがあります。原因を確認できたら、追加したprint()は削除しましょう。

RecursionErrorが出たときは、すぐに再帰回数の上限を増やすのではなく、終了条件、引数、呼び出し順序を1つずつ確認することが大切です。

RecursionErrorに関するよくある質問

RecursionErrorについて、初心者が疑問に感じやすい点をまとめます。エラーが出たときの確認にも役立ててください。

RecursionError: maximum recursion depth exceededとはどういう意味ですか?

RecursionError: maximum recursion depth exceededは、再帰による関数呼び出しが深くなり、Pythonで設定されている上限を超えたという意味です。

多くの場合、再帰処理に終了条件がないか、終了条件へ到達できないことが原因です。

エラーが出たときは、まず関数の中で同じ関数を呼び出している場所を探し、終了条件と引数の変化を確認しましょう。

終了条件を書いているのにRecursionErrorになるのはなぜですか?

終了条件があっても、実際にその条件へ到達できなければ再帰処理は止まりません。

たとえば、n <= 0で終了するコードで、再帰するたびにn + 1としている場合、値は0から遠ざかっていきます。

また、終了条件を確認する前に再帰関数を呼び出している場合も、処理を止めることができません。

終了条件が書かれているときは、次の2点を確認しましょう。

  1. 引数が終了条件へ近づいているか
  2. 終了条件が再帰呼び出しより前に書かれているか

Pythonの再帰回数の上限は何回ですか?

Pythonの再帰回数の上限は、実行環境によって異なる場合があります。

現在の上限は、sys.getrecursionlimit()を使って確認できます。

import sys

print(sys.getrecursionlimit())

実行すると、1000などの値が表示されます。

ただし、この値は関数を必ずその回数まで呼び出せるという意味ではありません。実際にRecursionErrorが発生するタイミングは、処理内容や実行環境によって変わることがあります。

sys.setrecursionlimit()を使えばRecursionErrorを解決できますか?

sys.setrecursionlimit()を使うと、再帰の上限を変更できます。

ただし、終了条件がない場合や、引数が正しく変化していない場合は、上限を増やしても根本的な解決にはなりません。

上限を変更する前に、次の順番で確認することをおすすめします。

  1. 終了条件があるか
  2. 引数が終了条件へ近づいているか
  3. 再帰呼び出しの位置が正しいか
  4. for文やwhile文へ書き換えられないか

再帰処理が正しく、扱うデータの都合で上限を超えている場合に限り、sys.setrecursionlimit()の使用を検討しましょう。

RecursionErrorと無限ループは同じですか?

RecursionErrorと無限ループは同じではありません。

RecursionErrorは、関数が自分自身を呼び出し続け、関数呼び出しの深さが上限を超えたときに発生します。

一方、無限ループは、while文などの終了条件が成立せず、同じ処理が繰り返され続ける状態です。

どちらも処理が終わらないように見えますが、確認する場所が異なります。RecursionErrorでは再帰関数を、無限ループではループの条件式と変数の変化を確認しましょう。

まとめ|RecursionErrorは終了条件と引数の変化を確認しよう

RecursionErrorは、再帰による関数呼び出しが深くなり、Pythonで設定されている上限を超えたときに発生するエラーです。

主な原因は、終了条件がない、引数が終了条件へ近づいていない、終了条件より先に再帰関数を呼び出していることです。

エラーが出たときは、終了条件、引数の変化、再帰呼び出しの位置を順番に確認しましょう。単純な繰り返し処理であれば、for文やwhile文への書き換えも有効です。

Pythonでよく出るエラーをまとめて確認したい方は、Pythonエラー一覧も参考にしてください。

あわせて読みたい
Pythonエラー一覧|よくあるエラーの意味・原因・直し方
Pythonエラー一覧|よくあるエラーの意味・原因・直し方
あわせて読みたい
Python入門講座|初心者向け無料カリキュラム
Python入門講座|初心者向け無料カリキュラム
記事URLをコピーしました