Pythonでグローバル変数を使用せずに再帰呼び出しの数を追跡する方法。たとえば、次の関数を変更して呼び出し数を追跡するにはどうすればよいですか?
def f(n):
if n == 1:
return 1
else:
return n * f(n-1)
print f(5)
これは、グローバルを使用しない巧妙なトリックです。関数自体にカウンターを隠しておくことができます。
def f(n):
f.count += 1
if n == 1:
return 1
else:
return n * f(n-1)
その後:
>>> f.count = 0 # initialize the counter
>>> f(5)
120
>>> f.count
5
>>> f(30)
265252859812191058636308480000000L
>>> f.count
35
とにかく、これは「これまでのすべての呼び出し」の場合を処理します。
デルナンが言ったように、これまでにすべての呼び出しが必要な場合、グローバルなしでは不可能なので、戻り値を追加するだけで、呼び出しの深さが必要であると想定しています。
def f(n):
if n == 1:
return 1,0
else:
x, call_depth= f(n-1)
return n * x, call_depth+1
複数の再帰呼び出しを処理している場合は、max(call_depth1, call_depth2)
(最長の呼び出しツリーの深さ)を実行するか、2つ(実際の呼び出しの総数)を合計することができます。
このメソッドは、関数が実行された合計回数を示します。
def f(n):
if hasattr(f,"count"):
f.count += 1
else:
f.count = 1
if n == 1:
return 1
else:
return n * f(n-1)
これは、グローバル変数の代わりにスタックを使用する方法です。示されているように、関数がそれ自体に対して行った再帰呼び出しの数だけでなく、最初の呼び出しを含む関数への呼び出しの数を集計します。これを行うには、をステートメントncalls += 1
の先頭に移動します。else
def f(n, ncalls=0):
ncalls += 1
if n == 1:
return 1, ncalls
else:
res, ncalls = f(n-1, ncalls)
return n * res, ncalls
for n in xrange(1, 6):
print 'f({}): {:4d} ({} calls)'.format(n, *f(n))
出力:
f(1): 1 (1 calls)
f(2): 2 (2 calls)
f(3): 6 (3 calls)
f(4): 24 (4 calls)
f(5): 120 (5 calls)
呼び出しの数を保持するための引数を追加することができます(可変のものである必要があります)。ここで、関数の開始時に増分されます。