Python学習チャンネル by PyQ

Pythonのオンライン学習プラットフォームPyQのオフィシャルブログです

【Pythonお悩み解決】RecursionError: maximum recursion depth exceededとは?

こんにちは、PyQサポートです。
今回は RecursionError: maximum recursion depth exceeded というエラーの原因を解説します。
再帰呼び出しをしている時に、このエラーになることがあります。早速、質問を見ていきましょう。

質問 RecursionError: maximum recursion depth exceededについて教えてください

nの階乗を計算する関数を作成し、きちんと計算できていました。コードを見やすくするために一部の計算を変数に代入しました。同じ計算をしているはずなのにRecursionError: maximum recursion depth exceededというエラーが出るようになりました。このエラーはどういうものなのでしょうか。

きちんと計算できるコード

def factorial(n):
    """nの階乗(n!)を返す"""
    return n * factorial(n - 1) if n > 1 else 1

print(factorial(4))

エラーになったコード(実行対象)

def factorial(n):
    """nの階乗(n!)を返す"""
    fn_1 = factorial(n - 1)
    return n * fn_1 if n > 1 else 1

print(factorial(4))

出たエラー(実行結果)

Traceback (most recent call last):
  File "sample.py", line 6, in <module>
    print(factorial(4))
  File "sample.py", line 3, in factorial
    fn_1 = factorial(n - 1)
  File "sample.py", line 3, in factorial
    fn_1 = factorial(n - 1)
  File "sample.py", line 3, in factorial
    fn_1 = factorial(n - 1)
  [Previous line repeated 996 more times]
RecursionError: maximum recursion depth exceeded

回答 「再帰呼び出しの最大回数を超えました」というエラーになっています

ある関数を実行したとき、その実行の中で同じ関数を呼びだすことを再帰呼び出しといいます。
その関数の実装にバグがあると、同じ関数を無限に呼びだそうとします。もし、無限に実行されると実行環境に重大な影響が出ます。
Pythonでは「再帰呼び出しの最大回数」が設定されており、関数の実行から戻らずに関数を無限に呼び出さないようになっています。
そして、この回数を超えて呼び出そうとするとRecursionErrorという例外が発生します。
「再帰呼び出しの最大回数」は、実行環境によって異なることがあります。下記を実行すると、この値を確認できます。

import sys

print(sys.getrecursionlimit())

実行結果(実行環境によって異なります)

1000

無限呼び出しをしようとする様子

エラーになるfactorial(n)では、最初に下記を計算しています。

    fn_1 = factorial(n - 1)

そのため、引数を4にして実行すると、下記のように無限に実行しようとします。

    fn_1 = factorial(3)
    fn_1 = factorial(2)
    fn_1 = factorial(1)
    fn_1 = factorial(0)
    fn_1 = factorial(-1)
    ...

エラーにならない方の下記の計算では、n > 1のときだけfactorial(n - 1)を計算するので無限には実行しません。

n * factorial(n - 1) if n > 1 else 1

なお、n * factorial(n - 1) if n > 1 else 1条件式という書き方で、一般には下記のように書きます。

1 if 条件 else2

条件式は、条件が成り立つときに式1の値になり、成り立たないときに式2の値になります。

参考:条件式 (Conditional Expressions) - 公式ドキュメント

補足

階乗の計算は、標準ライブラリーのmathモジュールの関数factorial()でも計算できます。

import math

print(math.factorial(4))

実行結果

24

特別な理由がなければ、mathモジュールの関数を使った方がよいでしょう。

再帰が書けるようになると、できることの幅が広がります。
PyQでは、下記のクエストで再帰を学べます。ちょっと難しいですがぜひトライしてみてください。

pyq.jp

Copyright ©2017- BeProud Inc. All rights reserved.