2010-09-02 2 views
10

я написал небольшой фрагмент кода, который вычисляет длину пути данного узла (например, его расстояние до корневого узла):Python: Странное поведение рекурсивной функции с аргументами ключевого слова

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) 

В настоящее время существует странная вещь, которая происходит с этой функцией (по крайней мере, это странно для меня): Calling node_depth в первый раз возвращает правильное значение. Однако, вызывая его во второй раз с тем же узлом, возвращает -1. В colored_nodes множество пусто в первом вызове, но содержит все узловые идентификаторы во втором вызове, которые были добавлены в ход первым:

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 

я упускаю некоторую Python-определенную вещь здесь, и это на самом деле, как предполагается, так?

Спасибо заранее,

Jena

+0

То же самое укусить меня, и я нашел ваш вопрос и еще одно объяснение деталей. http://stackoverflow.com/questions/1132941/least-astonishment-in-python-which-scope-is-the-mutable-default-argument-in – Yefei

ответ

15

«Значение по умолчанию» для параметра функции в Python конкретизируется во время функции декларации, а не каждый раз, когда функция вызывается. Вы редко хотите изменить значение параметра по умолчанию, поэтому часто полезно использовать что-то неизменяемое для значения по умолчанию.

В вашем случае вы можете захотеть сделать что-то вроде этого:

def node_depth(node, depth=0, colored_nodes=None): 
    ... 
    if colored_nodes is None: colored_nodes = set() 
+0

Это хорошая вещь, чтобы знать - большое спасибо. (И так как кто-то спросил: нет, это не домашнее задание.) – jena

+0

Спасибо за это! Отличный совет. @jena: Спасибо, что спросили об этом. :) – hayavuk

6

Это, потому что в Python, значения аргументов по умолчанию являются не вычисляется каждый раз, когда вызывается функция, но только один раз время определения функции. Таким образом, вы вызываете функцию с предварительно заполненным colored_nodes, установленным на каждом, но первом вызове после определения.

+0

Спасибо, я кое-что узнал. Теперь мой день завершен. – wheaties

Смежные вопросы