web-dev-qa-db-ja.com

Pythonの再帰? RuntimeError:Pythonオブジェクトの呼び出し中に最大再帰深度を超えました

可能性のある複製:
最大再帰深度?

コードに別の問題があります。私はVpythonで最初のプログラムを作成しており、2つのガスの混合のシミュレーションを行う必要があります。最初に境界線に問題がありましたが、今度はボール(ガス粒子を表す)が境界線内に留まると、いくつかの異なる誤りがあります。数秒後、エラーが発生します。これは、関数のソースコードの下に表示されています。コード:

def MovingTheBall(listOfBalls,position,numCell,flagOfExecution):
    flag = 0
    if flagOfExecution==0:
        positionTmp = position
    else:
        positionTmp = (position[0]+choice([-1,0,1]),position[1]+choice([-1,0,1]),0)
    for i in range( 0, len(listOfBalls) ):
        if positionTmp==listOfBalls[i].pos:
            flag=1


    if flag==1:
        return MovingTheBall(lista,(position[0]+choice([-1,0,1]),position[1]+choice([-1,0,1]),0),numCell,1)
    else:
        if positionTmp[0]==0 or positionTmp[0]>=numCell or positionTmp[0]<=-numCell or positionTmp[1]>=numCell or positionTmp[1]<=-numCell:
            return MovingTheBall(lista,(position[0]+choice([-1,0,1]),position[1]+choice([-1,0,1]),0),numCell,1)

        return positionTmp

エラーは:

    return MovingTheBall(listOfBalls,(position[0]+choice([-1,0,1]),position[1]+choice([-1,0,1]),0),numCell,1)
  File "gaz.txt", line 138, in MovingTheBall
    return MovingTheBall(listOfBalls,(position[0]+choice([-1,0,1]),position[1]+choice([-1,0,1]),0),numCell,1)
  File "gaz.txt", line 138, in MovingTheBall
    return MovingTheBall(listOfBalls,(position[0]+choice([-1,0,1]),position[1]+choice([-1,0,1]),0),numCell,1)
  File "gaz.txt", line 138, in MovingTheBall
    return MovingTheBall(listOfBalls,(position[0]+choice([-1,0,1]),position[1]+choice([-1,0,1]),0),numCell,1)
  File "gaz.txt", line 138, in MovingTheBall
    return MovingTheBall(listOfBalls,(position[0]+choice([-1,0,1]),position[1]+choice([-1,0,1]),0),numCell,1)
  File "gaz.txt", line 138, in MovingTheBall
    return MovingTheBall(listOfBalls,(position[0]+choice([-1,0,1]),position[1]+choice([-1,0,1]),0),numCell,1)
  File "gaz.txt", line 130, in MovingTheBall
    if positionTmp==listOfBalls[i].pos:
RuntimeError: maximum recursion depth exceeded while calling a Python object

誰かが私の機能を単純化する方法を考えることができますか?

関数while whileを実行します。

while 1:
        rate(20)
        for i in range(0,len(self.listOfBalls)):
            self.listOfBalls[i].pos=poruszanie(self.listOfBalls,self.listOfBalls[i].pos,self.numCell,0)
9
Emil Smęt

Pythonには、LISPなどの関数型言語で一般的なテール再帰の最適化がありません。 Pythonでは、再帰は999コールに制限されています( sys.getrecursionlimit を参照)。

999深度が予想よりも大きい場合は、実装に再帰を停止する条件がないかどうか、またはこのテストが一部のケースで間違っているかどうかを確認してください。

あえて言うと、Pythonでは、純粋な再帰的​​アルゴリズムの実装は正しくない/安全ではありません。 999に制限されたfib()実装は、実際には正しくありません。再帰を反復に変換することは常に可能であり、そうすることは簡単です。

多くの再帰的アルゴリズムでは深さが対数になる傾向があるため、多くの場合到達されません。アルゴリズムがそうではなく、再帰が999呼び出しよりも深いことが予想される場合は、2つのオプションがあります。

1)sys.setrecursionlimit(n)を使用して、プラットフォームで許可されている最大数まで再帰制限を変更できます。

sys.setrecursionlimit(limit)

Python=インタプリタスタックの最大深度を制限に設定します。この制限により、無限再帰がCスタックのオーバーフローを引き起こしてPythonをクラッシュさせるのを防ぎます。

可能な限りの上限は、プラットフォームによって異なります。深い再帰が必要なプログラムと、より高い制限をサポートするプラットフォームがある場合、ユーザーは制限をより高く設定する必要がある場合があります。制限が高すぎるとクラッシュする可能性があるため、これは注意して行う必要があります。

2)アルゴリズムを再帰的から反復的に変換することを試みることができます。再帰の深さがプラットフォームで許可されているよりも大きい場合、それが問題を修正する唯一の方法です。 インターネット上の段階的な説明 があり、CSの教育を受けている人にとっては簡単な操作であるはずです。問題が発生した場合は、新しい質問を投稿してください。

27
Paulo Scardine

再帰を反復に変更しました。

def MovingTheBall(listOfBalls,position,numCell):
while 1:
    stop=1
    positionTmp = (position[0]+choice([-1,0,1]),position[1]+choice([-1,0,1]),0)
    for i in range(0,len(listOfBalls)):
        if positionTmp==listOfBalls[i].pos:
            stop=0
    if stop==1:
        if (positionTmp[0]==0 or positionTmp[0]>=numCell or positionTmp[0]<=-numCell or positionTmp[1]>=numCell or positionTmp[1]<=-numCell):
            stop=0
        else:
            return positionTmp

良い作品:D

6
Emil Smęt

エラーはスタックオーバーフローです。これでこのサイトのベルが鳴るはずですよね?これは、poruszanieを呼び出すとporuszanieが再度呼び出され、再帰の深さが1増えるために発生します。2番目の呼び出しは、同じ関数をもう一度呼び出します。これは繰り返し発生し、そのたびに再帰の深さが増加します。

現在、プログラムの使用可能なリソースは限られています。各関数呼び出しは、スタックと呼ばれるものの上に一定量のスペースを取ります。スタックの最大の高さに達すると、スタックオーバーフローエラーが発生します。

4
pvoosten

これは、関数が自分自身に対してあまりにも多くの再帰呼び出しを行うときに発生するエラーです。これは、基本ケースが満たされないため(したがって、無限ループに陥る可能性があるため)、または単にそれ自体に多数の呼び出しを行うことによって行われている可能性があります。再帰呼び出しをwhileループに置き換えることができます。

0
mojzu