Python: странное поведение рекурсивной функции с аргументами ключевых слов - PullRequest
10 голосов
/ 03 сентября 2010

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

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)

Теперь с этой функцией происходит странная вещь (впо крайней мере это странно для меня): вызов 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 вещи, и это действительнотак и должно быть?

Заранее спасибо,

Йена

Ответы [ 2 ]

15 голосов
/ 03 сентября 2010

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

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

def node_depth(node, depth=0, colored_nodes=None):
    ...
    if colored_nodes is None: colored_nodes = set()
6 голосов
/ 03 сентября 2010

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

...