Questa è in realtà una funzione sorprendentemente interessante, e posso capire perché ti sta confondendo. Suppongo che tu stia cercando di capire la funzione nel suo complesso, e che in realtà non funzionerà bene qui.
Al momento, ci sono due parti per questa funzione: gestire il caso in cui è vuoto o c'è solo una lettera nella stringa e gestire il caso in cui ci sono almeno due lettere nella stringa. Tuttavia, questo è ingannevole perché applica in modo efficace un'operazione diversa a seconda di quante lettere ci sono nella stringa!
Quindi, pensiamo alla funzione in modo non ricorsivo: se la stringa è troppo corta, basta restituire la stringa.Altrimenti, applicare una qualche funzione a due volte a tutti tranne il primo carattere della stringa, quindi aggiungere il primo carattere alla fine del risultato. Non pensarlo come se fosse la stessa funzione, basti pensare che si tratta di una funzione sconosciuta.
in codice:
def f(s):
if len(s) <= 1:
return s
return other_f(other_f(s[1:])) + s[0]
nella tana del coniglio:
Quindi, come possiamo definire questo other_f
? Vediamo quale comportamento deve avere per determinate lunghezze di stringa. Se len(s)
è 2, allora sappiamo che s[1:]
è un carattere, quindi other_f
restituirà solo s[1:]
. Nel codice:
def f2(s): # For when len(s)==2
#if statement is not used
#return other_f(other_f(s[1:])) + s[0] becomes
#return other_f(other_f(s[1])) + s[0] becomes
#return other_f(s[1]) + s[0] becomes
return s[1] + s[0]
Semplicemente scambia le due lettere. Usiamo la stringa 'abc'
per vedere più facilmente quello che sta succedendo con la prossima:
def f3(s): # For when len(s)==3
#if statement is not used
#return other_f(other_f(s[1:])) + s[0] becomes
#return f2(f2('bc')) + 'a' becomes
#return f2('cb') + 'a' becomes
#return 'bc' + 'a'
return s[1:] + s[0]
Poiché la funzione applicata a 'bc' li scambia e si applica due volte, la funzione stessa disfa. Quindi in questo caso abbiamo semplicemente messo la prima lettera alla fine della stringa.
def f4(s): # For when len(s)==4
#return f3(f3(s[1:])) + s[0] becomes
#return f3(f3('bcd')) + 'a' becomes
#return f3('cdb') + 'a' becomes
#return f3('dbc') + 'a' becomes
#'dbca'
return s[3] + s[1:3] + s[0] # swap first and last letter
def f5(s): # For when len(s)==5
#return f4(f4(s[1:])) + s[0]
#return f4(f4('bcde')) + 'a'
#swapping first and last letter twice just swaps then swaps back
#return 'bcde' + 'a'
return s[1:] + s[0]
così sembra che abbiamo un bel modello di andare qui - se la stringa ha un numero pari di lettere, scambiare la prima e l'ultima lettera. Se ha un numero dispari di lettere, sposta la prima lettera fino alla fine!
... No. Quel modello termina con f5
. Se esegui la funzione con stringhe come 'abcd ...' puoi facilmente vedere come ogni livello sposta le lettere in giro.
f | output
----------
f6|'defbca'
f7|'cdbfgea'
f8|'cgefbhda'
f9|'fecihbgda'
Quindi, come si può vedere, per le stringhe più lunghe le lettere sono criptati intorno abbastanza bene diverso da primo carattere sempre fino a raggiungere la fine della stringa. Il modo migliore per pensarlo è che (con una singola riga di codice) sei riuscito a scrivere una funzione diversa per ogni lunghezza di stringa (con alcune funzioni che si comportano allo stesso modo, come f3
e f5
). Ogni funzione dipende dalla funzione sopra di essa, quindi, poiché f6
in giù abbastanza bene randomizza la stringa, ogni ulteriore funzione dovrebbe anche randomizzare abbastanza bene la stringa.
Hai provato a usare carta e penna? Non è estremamente complesso, quindi ti consiglio di disegnare lo stack delle chiamate con lo stato corrente della variabile. Sarebbe meglio per te scoprirlo da solo che qualcuno te lo spiegasse. – amza
@stazima - Dato che ci ha già passato qualche ora, penso che l'OP sarà meglio con spiegazioni più esplicite, altrimenti finirà per sbattere la testa contro lo stesso muro che sta colpendo finora. – rmunn