2010-09-02 17 views
10

que he escrito un pequeño fragmento que calcula la longitud de la trayectoria de un nodo dado (por ejemplo, su distancia al nodo raíz):Python: Extraño comportamiento de la función recursiva con argumentos clave

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) 

Ahora hay una Algo extraño sucede con esa función (al menos es extraño para mí): al llamar a node_depth por primera vez, se devuelve el valor correcto. Sin embargo, llamarlo por segunda vez con el mismo nodo devuelve -1. Los colored_nodes conjunto está vacío en la primera llamada, pero contiene todos los IDs de nodo en la segunda llamada que se han añadido durante la primera de ellas:

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 

Me estoy perdiendo algo específico de Python aquí y esto es realmente supone que ser de esa manera?

Gracias de antemano,

Jena

+0

Lo mismo me muerde y encontré su pregunta y otra explicación de detalles. http://stackoverflow.com/questions/1132941/least-astonishment-in-python-which-scope-is-the-mutable-default-argument-in – Yefei

Respuesta

15

el "valor por defecto" para un parámetro de la función en Python se crea una instancia en tiempo de declaración de la función, no cada vez que la función se llama. Rara vez desea mutar el valor predeterminado de un parámetro, por lo que a menudo es una buena idea usar algo inmutable para el valor predeterminado.

En su caso es posible que desee hacer algo como esto:

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

Eso es bueno saber, muchas gracias. (Y desde que alguien preguntó: No, esta no es una tarea.) – jena

+0

¡Gracias por esto! Gran consejo. @jena: gracias por preguntar esto también. :) – hayavuk

6

Esto es, porque en Python, los valores de los argumentos por defecto son no evaluado cada vez que la función se llama, pero sólo una vez en tiempo de definición de función. Entonces, de hecho, está llamando a la función con un colored_nodes prellenado configurado en todas las llamadas menos en la primera después de la definición.

+0

Gracias, aprendí algo. Ahora mi día está completo. – wheaties

Cuestiones relacionadas