Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: Strange behaviour of recursive function with keyword arguments

I've written a small snippet that computes the path length of a given node (e.g. its distance to the root node):

def node_depth(node, depth=0, colored_nodes=set()):
    """
    Return the length of the path in the parse tree from C{node}'s position
    up to the root node. Effectively tests if C{node} is inside a circle
    and, if so, returns -1.

    """
    if node.mother is None:
        return depth
    mother = node.mother
    if mother.id in colored_nodes:
        return -1
    colored_nodes.add(node.id)
    return node_depth(mother, depth + 1, colored_nodes)

Now there is a strange thing happening with that function (at least it is strange to me): Calling node_depth for the first time returns the right value. However, calling it a second time with the same node returns -1. The colored_nodes set is empty in the first call, but contains all node-IDs in the second call that have been added during first one:

print node_depth(node) # -->  9
# initially colored nodes --> set([])
print node_depth(node) # --> -1
# initially colored nodes --> set([1, 2, 3, 38, 39, 21, 22, 23, 24])

print node_depth(node, colored_nodes=set()) # --> 9
print node_depth(node, colored_nodes=set()) # --> 9

Am I missing some Python-specific thing here and this is really supposed to be that way?

Thanks in advance,

Jena

like image 211
jena Avatar asked Sep 02 '10 23:09

jena


People also ask

What are the disadvantages of recursion in Python?

Disadvantages of RecursionRecursive calls are expensive (inefficient) as they take up a lot of memory and time. Recursive functions are hard to debug.

Why is Python not good for recursion?

This is because Python has a function call overhead where the interpreter does dynamic type checking of function arguments done before and after the function call, which results in additional runtime latency.

How is recursive function different from normal function in Python?

In Python, it's also possible for a function to call itself! A function that calls itself is said to be recursive, and the technique of employing a recursive function is called recursion. It may seem peculiar for a function to call itself, but many types of programming problems are best expressed recursively.

What is keyword argument in Python with example?

Keyword arguments (or named arguments) are values that, when passed into a function, are identifiable by specific parameter names. A keyword argument is preceded by a parameter and the assignment operator, = . Keyword arguments can be likened to dictionaries in that they map a value to a keyword.


2 Answers

The "default value" for a function parameter in Python is instantiated at function declaration time, not every time the function is called. You rarely want to mutate the default value of a parameter, and so it's often a good idea to use something immutable for the default value.

In your case you may want to do something like this:

def node_depth(node, depth=0, colored_nodes=None):
    ...
    if colored_nodes is None: colored_nodes = set()
like image 153
Laurence Gonsalves Avatar answered Nov 15 '22 10:11

Laurence Gonsalves


This is, because in Python, the default argument values are not evaluated each time the function is called, but only once at function definition time. So effectively, you are calling the function with a pre-filled colored_nodes set on every but the first call after definition.

like image 6
Dirk Avatar answered Nov 15 '22 11:11

Dirk