2012-07-06 28 views
20

acabo de empezar a aprender Python (V3.2.3) y se han encontrado con un problema extraño en el return en esta función:retorno en función recursiva

def test(x): 
    if x > 9 : 
     test(x - 10) 
    else: 
     print('real value',x) 
     return x 

x = int(input()) 
y = test(x) 
print('this should be real value',y) 

Cuando corro, me sale:

45 
real value 5 
this should be real value None 

Pero lo que esperaba:

45 
real value 5 
this should be real value 5 

he intentado añadir return x fuera del if y obtuve el valor de entrada predeterminado. ¿Alguien puede explicar cómo funciona el return?

+3

Es exactamente lo mismo que con una llamada no recursiva: si desea propagar el valor de retorno de la función que llamó, debe hacerlo usted mismo, con la palabra clave 'return'. Llamar a una función produce su valor de retorno, pero depende de usted hacer algo con ese valor de retorno, ya sea que la función llamada sea recursiva o no. –

Respuesta

13

La devolución está sangrada, por lo que solo se ejecuta en la rama else. Si se toma la primera rama, la función devuelve implícitamente None.

necesita cambiar esto a

return test(x-10) 
+0

entonces, ¿esto significa que necesito tener devolución incluso en la condición falsa no ejecutada? –

+1

@AlexKey: Sí. Como a 'y' se le asigna el valor de la primera llamada de función solamente. Esto no es algo exclusivo de Python. La única parte que es exclusiva de Python es que las funciones devuelven 'None' implícitamente cuando no hay declaración return. –

4

Usted se olvidó de devolver el valor cuando x > 9. Sin el valor de retorno, la función "devolverá" None.

+0

así que, en resumen, tengo que devolver el rendimiento tanto en la condición es? –

+0

@AlexKey: en el código anterior, sí, devolverá el valor de evaluación 'prueba (x - 10)' – nhahtdh

34

Invoque test(45). Esto prueba si 45 > 9, que es verdadero, por lo que invoca test(35) (45 - 10), sin devolver su resultado. Lo mismo ocurre con test(25) y test(15), hasta que finalmente se invoca test(5).

Esto imprime 'valor real 5', y luego devuelve 5. Pero devolver un resultado de una función siempre lo devuelve a la persona que llama directamente a esta función. No salta inmediatamente a través de varias llamadas; después de todo, la persona que llama puede querer hacer algo con el resultado devuelto antes de devolver algo al es llamador. Sin embargo, en este caso, solo test(5) devuelve algo; todos los demás llaman al test(x - 10), espere a que vuelva, ignore lo que devuelva, y luego (implícitamente) devuelva None. Dado que la invocación más externa test(45) es uno de estos casos, lo que obtienes es None.

He aquí un intento de una visualización de lo que sucede:

test(45): 
| test(35): 
| | test(25): 
| | | test(15): 
| | | | test(5): 
| | | | | print('real value',5) 
| | | | | return 5 to test(15) 
| | | | return None to test(25) 
| | | return None to test(35) 
| | return None to test(45) 
| return None 

no llamó test(5) en el intérprete, test(5) fue llamado desde dentro de otra llamada a la función. Entonces el retorno de test(5) va a que llama a la función. El hecho de que se trate de una función que se llama a sí misma es completamente irrelevante. Te obtener exactamente los mismos resultados si su código se veía así:

def test45(x): 
    if x > 9 : 
     test35(x - 10) 
    else: 
     print('real value',x) 
     return x 

def test35(x): 
    if x > 9 : 
     test25(x - 10) 
    else: 
     print('real value',x) 
     return x 

def test25(x): 
    if x > 9 : 
     test15(x - 10) 
    else: 
     print('real value',x) 
     return x 

def test15(x): 
    if x > 9 : 
     test5(x - 10) 
    else: 
     print('real value',x) 
     return x 

def test5(x): 
    if x > 9 : 
     print 'No more tests :(' 
    else: 
     print('real value',x) 
     return x 

La prueba (x) se llama a la función con 'x = 45' es igual que llamar test45(45). Espero que pueda ver por qué es obvio que None debe devolverse cuando la recursión no esté involucrada en. Bueno, cuando se trata de recursividad, nada cambia. La instrucción return no sabe ni le importa si regresa de una función invocada recursivamente, se comporta exactamente de la misma manera en cualquier caso.

De hecho, la recursividad no es nada "especial" en absoluto; se comporta exactamente de la misma manera que las llamadas a funciones ordinarias. Recibe información de lo que lo llamó por medio de argumentos, y devuelve información a la cosa que lo llamó al regresar. Si no devuelve algo (quizás solo en un brazo de un if), se devolverá None a su interlocutor, independientemente de si llama a cualquier otra función en esa rama, independientemente de lo que pueda devolver esa función si llama algo, e independientemente de si la función que llamas pasa a ser la misma función en la que estás dentro.