Python/Iterazione: differenze tra le versioni

Contenuto cancellato Contenuto aggiunto
Riga 111:
</source>
 
<source lang=python>
>>> l=[1, 3, 5, 7, 9]
>>> print somma(l)
25
</source>
 
Ora se volessi la media dei numeri contenuti in una lista, posso scrivere la funzione:
 
<source lang=python>
def media(lista):
return somma(lista)/float(len(lista))
 
>>> print media(l)
5.0
</source>
 
Peccato solo che che, per questioni di efficienza, Python abbia implementato tra le funzioni native la funzione '''add''' che produce lo stesso risultato della nostra funzione '''somma'''.
 
Se volessi implementare una ricerca sequenziale in una lista, potrei usare '''for''' nel seguente modo:
 
<source lang=python>
def contenuto(elemento, lista):
result=True
for e in lista:
if e==elemento:
break
else:
result=False
return result
 
>>> print contenuto('pippo', l)
True
>>> print contenuto('Pippo', l)
False
</source>
 
Se volessi avere non una funzione che mi dice semplicemente se l'elemento è contenuto in una lista ma qual è la sua posizione, potrei combinare l'iteratore '''for''' con la funzione '''enumerate''' che restituisce la coppia: ''posizione'', ''elemento'':
 
<source lang=python>
def posizione(elemento, lista):
for i, e in enumerate(lista):
if e==elemento:
result=i
break
else:
result=-1
return result
 
>>> print posizione('pluto', l)
1
>>> print posizione('pippo', l)
0
>>> print posizione('Pippo', l)
-1
</source>
 
Anche qui peccato che Guido ci abbia preceduti e sempre per questioni di efficienza abbia implementato l'istruzioine '''in''' e il metodo '''index''' che fanno all'incirca quello che fanno le nostre funzioni '''contenuto''' e '''posizione'''.
 
== for: la trappola ==
 
L'iteratore '''for''' presenta un trabocchetto... Per capirlo, partiamo da un esempio. Abbiamo una lista che contiene vari numeri, vogliamo togliere tutti quelli pari:
 
<source lang=python>
def toglipari(lista):
for e in lista:
if e%2==0:
lista.remove(e)
 
>>> num=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> toglipari(num)
>>> print num
[1, 3, 5, 7, 9]
</source>
 
Sembra funzionare perfettamente, ma non è così! Se tentiamo di togliere i numeri pari da quest'altra lista:
 
<source lang=python>
>>> num1=[0, 1, 2, 4, 5, 6, 7, 8, 9]
>>> toglipari(num1)
>>> num1
[1, 4, 5, 7, 9]
</source>
 
otteniamo un risultato sconcertante!
 
Cosa è successo, come mai a volte funziona e a volte no? Questi sono gli errori più insidiosi, appaiono solo a volte, e, tipicamente, quando fanno più danno.
 
Il fatto è che si deve assolutamente evitare di modificare la sequenza su cui l'iteratore '''for''' sta lavorando.
 
Nel primo caso ('''num=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]''') viene controllato il primo elemento di '''num''', è pari e viene tolto. Ora il primo elemento è 1 e viene controllato il secondo, vale 2, è pari e viene tolto, ora il primo elemento è 1 e il secondo è 3, viene controllato il terzo che è pari e viene tolto...
 
Nel secondo caso ('''num1=[0, 1, 2, 4, 5, 6, 7, 8, 9]''') viene controllato il primo elemento di '''num1''', è pari e viene tolto. Ora il primo elemento è 1 e viene controllato il secondo, vale 2, è pari e viene tolto, ora il primo elemento è 1 e il secondo è 4, viene controllato il terzo che è 5, è dispari e viene lasciato, poi viene controllato il quarto elemento...
 
Regola fondamentale per non cadere nella trappola è: "mai modificare una lista mentre si sta iterando su di essa".
 
Allora, come si può realizzare l'operazione precedente? Basta iterare su una lista e modificarne un'altra, inizialmente identica. Ma come costruire una lista identica ad una già presente? Ci sono due costrutti Python che permettono di farlo:
 
<source lang=python>
lista1=lista[:] # lista1 contiene tutti gli elementi di lista
 
lista2=list(lista) # lista2 è una copia di lista
</source>
 
Tenendo conto di questo si può ruiscrivere il comando precedente e provare che funziona:
 
<source lang=python>
def toglipari(lista):
for e in lista[:]:
if e%2==0:
lista.remove(e)
</source>
 
<source lang=python>
>>> num=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> toglipari(num)
>>> print num
[1, 3, 5, 7, 9]
>>> num1=[0, 1, 2, 4, 5, 6, 7, 8, 9]
>>> toglipari(num1)
>>> print num1
[1, 5, 7, 9]
>>> num2=[0, 1, 3, 2, 6, 4, 5, 2, 7, 8, 2, 9]
>>> toglipari(num2)
>>> print num2
[1, 3, 5, 7, 9]
</source>
 
[[Categoria:Python|Selezione]]