PDA

View Full Version : [Python] Risolto un problema se ne crea un altro


Heretic Curse
17-05-2013, 17:23
Ok, vi dico subito: rilassatevi :) . Questa volta non ho un codice che non funziona per via della mia sbadataggine, semplicemente sono andato avanti di circa mezzo capitolo di "Pensare in Python", e ho trovato un codice che, per quanto funzioni, non riesco a comprendere.

class Nodo:
def __init__(self, Contenuto=None, ProssimoNodo=None):
self.Contenuto = Contenuto
self.ProssimoNodo = ProssimoNodo

def __str__(self):
return str(self.Contenuto)

def StampaInversa(Lista):
if Lista == None: return
Testa = Lista
Coda = Lista.ProssimoNodo
StampaInversa(Coda)
print Testa,

Nodo1 = Nodo(1)
Nodo2 = Nodo(2)
Nodo3 = Nodo(3)
Nodo1.ProssimoNodo = Nodo2
Nodo2.ProssimoNodo = Nodo3
StampaInversa(Nodo1)


E viene restituito:
3 2 1

che è proprio quello che voglio. Tuttavia non ho ben capito perché questo codice funziona:
-Testa = Nodo1
-Coda = Nodo2
-Testa = Nodo2
-Coda = Nodo3
-la condizione risulta positiva e quindi si attiva return, e penso che ciò che non capisco riguardi questa funzione
-(supponendo che in qualche strano modo vengano saltate le tre righe successive) viene stampato Testa, ovvero Nodo3. Com'è che vengono restituiti pure gli attributi degli altri Nodi?

kwb
17-05-2013, 19:29
Ok, vi dico subito: rilassatevi :) . Questa volta non ho un codice che non funziona per via della mia sbadataggine, semplicemente sono andato avanti di circa mezzo capitolo di "Pensare in Python", e ho trovato un codice che, per quanto funzioni, non riesco a comprendere.

class Nodo:
def __init__(self, Contenuto=None, ProssimoNodo=None):
self.Contenuto = Contenuto
self.ProssimoNodo = ProssimoNodo

def __str__(self):
return str(self.Contenuto)

def StampaInversa(Lista):
if Lista == None: return
Testa = Lista
Coda = Lista.ProssimoNodo
StampaInversa(Coda)
print Testa,

Nodo1 = Nodo(1)
Nodo2 = Nodo(2)
Nodo3 = Nodo(3)
Nodo1.ProssimoNodo = Nodo2
Nodo2.ProssimoNodo = Nodo3
StampaInversa(Nodo1)


E viene restituito:
3 2 1

che è proprio quello che voglio. Tuttavia non ho ben capito perché questo codice funziona:
-Testa = Nodo1
-Coda = Nodo2
-Testa = Nodo2
-Coda = Nodo3
-la condizione risulta positiva e quindi si attiva return, e penso che ciò che non capisco riguardi questa funzione
-(supponendo che in qualche strano modo vengano saltate le tre righe successive) viene stampato Testa, ovvero Nodo3. Com'è che vengono restituiti pure gli attributi degli altri Nodi?

Il metodo StampaInversa è un metodo ricorsivo, ovvero che richiama se stesso.
Prima che venga fatta la prima chiamata a StampaInversa hai Nodo1, Nodo2 completamente definiti ( ovvero hanno sia un attributo Contenuto che un attributo ProssimoNodo definito ). Nodo3 invece ha solo l'attributo Contenuto definito, mentre ProssimoNodo è uguale a None ( come indicato tra i parametri del costruttore ).

Detto ciò, quando chiami per la prima volta StampaInversa questo è quello che succede:
1. Nodo1 è uguale a None? FALSO
2. Imposti Testa = Nodo1
3. Imposti Coda = Nodo2
4. Chiama StampaInversa(Nodo2) [Nota che qua si chiama Coda, ma Coda= Nodo2]

5. Nodo2 è uguale a None? FALSO
6. Imposti Testa = Nodo2
7. Imposti Coda = Nodo3
8. Chiama StampaInversa(Nodo3) [Nota che qua si chiama Coda, ma Coda= Nodo3]

9. Nodo3 è uguale a None? FALSO
10. Imposti Testa = Nodo3
11. Imposti Coda = None
12. Chiama StampaInversa(None) [Nota che qua si chiama Coda, ma Coda= None]

13. None è uguale a None? VERO -> Esci dalla funzione

14. Ora siamo dentro StampaInversa di Nodo3. Subito la chiama alla funzione StampaInversa(None) c'è print Testa, quindi:
15. Stampa Nodo3
16. Esci da StampaInversa
17. Stampa Nodo2
18. Esci da StampaInversa
19. Stampa Nodo1
20. Esci da StampaInversa

21. Esci dal programma

Heretic Curse
17-05-2013, 20:05
Il metodo StampaInversa è un metodo ricorsivo, ovvero che richiama se stesso.
Prima che venga fatta la prima chiamata a StampaInversa hai Nodo1, Nodo2 completamente definiti ( ovvero hanno sia un attributo Contenuto che un attributo ProssimoNodo definito ). Nodo3 invece ha solo l'attributo Contenuto definito, mentre ProssimoNodo è uguale a None ( come indicato tra i parametri del costruttore ).

Detto ciò, quando chiami per la prima volta StampaInversa questo è quello che succede:
1. Nodo1 è uguale a None? FALSO
2. Imposti Testa = Nodo1
3. Imposti Coda = Nodo2
4. Chiama StampaInversa(Nodo2) [Nota che qua si chiama Coda, ma Coda= Nodo2]

5. Nodo2 è uguale a None? FALSO
6. Imposti Testa = Nodo2
7. Imposti Coda = Nodo3
8. Chiama StampaInversa(Nodo3) [Nota che qua si chiama Coda, ma Coda= Nodo3]

9. Nodo3 è uguale a None? FALSO
10. Imposti Testa = Nodo3
11. Imposti Coda = None
12. Chiama StampaInversa(None) [Nota che qua si chiama Coda, ma Coda= None]

13. None è uguale a None? VERO -> Esci dalla funzione

14. Ora siamo dentro StampaInversa di Nodo3. Subito la chiama alla funzione StampaInversa(None) c'è print Testa, quindi:
15. Stampa Nodo3
16. Esci da StampaInversa
17. Stampa Nodo2
18. Esci da StampaInversa
19. Stampa Nodo1
20. Esci da StampaInversa

21. Esci dal programma

Fino al 13 avevo capito (anche se l'ho spiegato un po' con i piedi). Adesso vediamo se ho compreso bene il resto: in pratica quando la condizione diventa vera esce dalla funzione, che però era quella interna che agiva su None, e così rientra nella StampaInversa di Nodo3, la completa col print, rientra in quella di Nodo2, completa col print, e poi idem con Nodo1.
Riformulando: le StampaInversa restano in stasi finché Lista non è uguale a None, così interrompe quella attuale (che agiva appunto su None) e poi ritorna sulle altre partendo dalla più recente, così da compierle a ritroso.

Grazie mille ;)

kwb
17-05-2013, 20:21
Fino al 13 avevo capito (anche se l'ho spiegato un po' con i piedi). Adesso vediamo se ho compreso bene il resto: in pratica quando la condizione diventa vera esce dalla funzione, che però era quella interna che agiva su None, e così rientra nella StampaInversa di Nodo3, la completa col print, rientra in quella di Nodo2, completa col print, e poi idem con Nodo1.
Riformulando: le StampaInversa restano in stasi finché Lista non è uguale a None, così interrompe quella attuale (che agiva appunto su None) e poi ritorna sulle altre partendo dalla più recente, così da compierle a ritroso.

Grazie mille ;)
Si in buona sostanza è così.