开发者

Is there a way to tell if I'm using recursion in Python?

开发者 https://www.devze.com 2023-01-17 14:27 出处:网络
I\'m writing a function to traverse the user\'s file system and create a tree representing that directory (the tree is really a TreeView widget in Tkinter, but that\'s functionally a tree).

I'm writing a function to traverse the user's file system and create a tree representing that directory (the tree is really a TreeView widget in Tkinter, but that's functionally a tree).

The best way I can think of doing t开发者_运维知识库his is recursion. However, one of my cases in the function requires me to know if it is the "original" function call, in which case the files have no parent node, or if it is a "recursive" function call, i.e. a call that has been made by the function itself, so that I can give those files an appropriate parent node.

Is there any way in Python to ask a function, "hey, are you recursive?" or "hey, where were you called from?"


Pretty much the same as in every other language - in your case, you pass a reference to the parent and check if it is None. If so, you create a proper parent node.


one of my cases in the function requires me to know if it is the "original" function call, in which case the files have no parent node

This seems like a strange case of too much work for the specific function. You have to construct the tree - why do you need to know where it's attached? Why not just construct the nodes you're responsible for and return them?

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

And walk the tree again when you receive it?

If you really want to integrate it, just pass the parent:

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:
        .....


It should be easy and common, to include a reference to the parent or some level information along with the call to the recursion.

One other way (which I wouldn't prefer, though) is to use pythons inspect module, which lets you inspect e.g. the call stack. An example:

#!/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)

Would print:

4 <module>
3 fib
2 fib
1 fib
0 fib
1 fib
2 fib
1 fib
0 fib


You can access the memory stack through the inspectmodule.

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()

You'll get an index out of range error if you attempt to call it from __main__.

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


I really wonder why you make this so complicated. You can simply split the function in a recursive and a not recursive part! Here is a simple example:

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)

In reality you don't even need many arguments to the recursive function because it is a closure and can use anything you defined in it's namespace.

0

精彩评论

暂无评论...
验证码 换一张
取 消