1


0

Pythonで再帰を使用しているかどうかを確認する方法はありますか?

ユーザーのファイルシステムを走査して、そのディレクトリを表すツリーを作成する関数を作成しています(ツリーは実際にはTkinterのTreeViewウィジェットですが、機能的にはツリーです)。

これを行うための最良の方法は、再帰です。 ただし、関数の私のケースの1つでは、それが「元の」関数呼び出しであるかどうかを知る必要があります。その場合、ファイルに親ノードがないか、「再帰」関数呼び出し、つまり これらのファイルに適切な親ノードを提供できるように、関数自体によって行われた呼び出し。

Pythonに関数を尋ねる方法はありますか、「ねえ、あなたは再帰的ですか?」または「ねえ、どこから呼ばれたの?」

5 Answer


7


他のすべての言語とほとんど同じです-あなたの場合、親に参照を渡し、それがNoneかどうかを確認します。 その場合、適切な親ノードを作成します。


4


_ 関数の私のケースの1つでは、それが「元の」関数呼び出しであるかどうかを知る必要があります。その場合、ファイルには親ノードがありません _

これは、特定の機能に対してあまりにも多くの作業を行うという奇妙なケースのようです。 ツリーを構築する必要があります-なぜそれが接続されているかを知る必要があるのですか? 担当するノードを構築して返すだけではどうですか?

def make_tree(path):
    return [
        make_tree(os.path.join(path, element))
        for element in get_elements(path)]

そして、あなたはそれを受け取ったら再び木を歩きますか?

本当に統合したい場合は、親を渡すだけです:

def make_tree(path, parent_node = None):
    new_node = Node(...)
    for ....:
        make_tree(path+..., new_node)

    if parent_node is not None:
        parent_node.add(new_node)
    else:
        .....


1


親への参照または何らかのレベルの情報を再帰呼び出しとともに含めるのは簡単で一般的です。

もう1つの方法(しかし、私は好まないでしょう)はpythonsの `inspect`モジュールを使用することです。 呼び出しスタック。 例:

#!/usr/bin/env python

import inspect

def whocalled():
    return inspect.stack()[2][3]

def fib(n):
    print n, whocalled()
    if n < 2:
        return n
    return fib(n - 1) + fib(n - 2)

if __name__ == '__main__':
    fib(4)

印刷します:

4
3 fib
2 fib
1 fib
0 fib
1 fib
2 fib
1 fib
0 fib


1


`inspect`モジュールを介してメモリスタックにアクセスできます。

import inspect

def whoami():
    '''Returns the function name of the caller.'''

    return inspect.stack()[1][3] #Stack data for the name of the function

def caller():
    '''Returns the caller of a function.'''

    return inspect.stack()[2][3] #Stack data for the name of whatever calls this

caller = caller()

`main`から呼び出そうとすると、範囲外のインデックスエラーが発生します。

when the caller of the function != whoami() -> no longer recursing.


1


なぜあなたはこれをそんなに複雑にしているのだろう。 関数を再帰部分と非再帰部分に単純に分割できます! これは簡単な例です:

def countdown(n):
    " original function "
    print "Ok, start the countdown (not recursive)"

    msg = "We are at"

    def recursive( x ):
        " recursive part "
        if x >= 0:
            print msg, x, "(recursive)"
            return recursive(x-1)

    return recursive(n)

countdown(10)

実際には、クロージャであり、その名前空間で定義したものをすべて使用できるため、 `recursive`関数に対する多くの引数さえ必要ありません。