2016-04-16 10 views
1

私はエクササイズのためのテスト関数を書いて、関数が正しく実装されていることを確認します。
私は不思議に思っています。再帰的に実装されているかどうかを確認するために、関数 "foo"が与えられていますか?
再帰関数をカプセル化して使用する場合は、それもカウントされます。例:関数がPythonで再帰的であるかどうかを調べる方法はありますか?

def foo(n): 
    def inner(n): 
     #more code 
     inner(n-1) 
    return inner(n) 

これは再帰的とも考えられます。
このチェックを実行するには、外部のテスト関数を使用します。関数の元のコードを変更することなく。

+1

「foo()」を呼び出す 'foo()'を定義したとしましょう。 'bar = foo'と言って新しい' foo() 'を定義します。 'bar()'を呼び出すと、それ自身ではなく、 'foo'を呼び出します。この関数は名前を持つ関数を呼び出すため再帰的ですが、同じ名前の別の関数になる可能性があります。 – zondo

+1

@AlexHall:Pythonでの再帰をチェックする唯一の方法です*、実際に起こっているとき*。再帰呼び出しに使用される名前はいつでも*何かにリバウンドする可能性があるためです。 –

+1

@MartijnPieters少なくともOPの問題の解決策は、ほとんどの場合に機能します。ゾンドの異議は非常に具体的であり、必ずしもOPには関係しません。 –

答えて

3

ソリューション:

from bdb import Bdb 
import sys 

class RecursionDetected(Exception): 
    pass 

class RecursionDetector(Bdb): 
    def do_clear(self, arg): 
     pass 

    def __init__(self, *args): 
     Bdb.__init__(self, *args) 
     self.stack = set() 

    def user_call(self, frame, argument_list): 
     code = frame.f_code 
     if code in self.stack: 
      raise RecursionDetected 
     self.stack.add(code) 

    def user_return(self, frame, return_value): 
     self.stack.remove(frame.f_code) 

def test_recursion(func): 
    detector = RecursionDetector() 
    detector.set_trace() 
    try: 
     func() 
    except RecursionDetected: 
     return True 
    else: 
     return False 
    finally: 
     sys.settrace(None) 

使用例/テスト:基本的に

def factorial_recursive(x): 
    def inner(n): 
     if n == 0: 
      return 1 
     return n * factorial_recursive(n - 1) 
    return inner(x) 


def factorial_iterative(n): 
    product = 1 
    for i in xrange(1, n+1): 
     product *= i 
    return product 

assert test_recursion(lambda: factorial_recursive(5)) 
assert not test_recursion(lambda: factorial_iterative(5)) 
assert not test_recursion(lambda: map(factorial_iterative, range(5))) 
assert factorial_iterative(5) == factorial_recursive(5) == 120 

test_recursionは、引数なしで呼び出し可能になります、それを呼び出し、その呼び出し可能の実行中の任意の時点であればTrueを返します。同じコードがスタックに2回、それ以外の場合はFalseになりました。私はそれがOPが望んでいるものではないことが判明する可能性が高いと思います。例えば、特定の瞬間に同じコードがスタックに10回現れるかどうかをテストするために簡単に変更できます。

関連する問題