Python, le liste e i cicli for (e non riesco mai a ricordarmi)

Yep! proprio così. Ci sono delle cose che anche se ti sono già capitate (a me più volte) e finanche se te l’hanno già detto (a me più volte) non riesci a ricordartele. O capita solo a me? Oggi voglio scrivere di una di queste così me ne ricorderò. O se me lo faranno notare quando mi capiterà potrò dire “lo so; l’ho anche scritto, qui!”.

Non so voi ma alle volte la bontà di un’elaborazione (un run) viene valutata da un valore finale o la forma di una linea (o un punto) su un grafico. O sono solo io? A volte il valore finale non cambia al cambiare dei dati di input o il grafico è subito esatto o sempre sbagliato… Ecco parlo di uno di quei casi.

È una cosa semplice, la sanno tutti (anch’io) e nell’esempio qui sotto si vede subito dov’è il bug ma in un programma vero, scritto come al solito non è immediatamente evidente e bisogna andarlo a stanare. E (o capita solo a me?) i propri errori sono quelli che sono i più nascosti. Ma basta con l’intro giustificativa inizio.

Uno script se non limitato a poche righe sarà organizzato in funzioni, che possono poi essere contenute in classi. Mi occuperò solo delle funzioni, ecco quad() una funzione elementare per fare il quadrato di un numero:

def quad(n):
  return n * n

Funziona proprio come ci si aspetta (uso la REPL):

$ python3 -q
>>> def quad(n):
...   return n * n
...
>>> i = 5
>>> q = quad(i)
>>> q
25
>>> i
5

quad(), essendo Python un tipper ducko fa più di quel che si pensa:

>>> type(i)
<class 'int'>
>>> type(q)
<class 'int'>
>>> f = 4.2
>>> r = quad(f)
>>> r
17.64
>>> type(f)
<class 'float'>
>>> type(r)
<class 'float'>

In ogni caso i parametri (i e f) vengono passati per valore. Ecco una versione ridondante, con print di debug; tipo di istruzioni che possono capitare se la funzione è complessa e si è pasticcioni:

def quadp(n):
  n *= n
  print("dentro", n)
  return n

Vediamola in azione:

>>> n = 8
>>> s = quadp(n)
dentro 64
>>> s
64
>>> n
8

OK! una cosa simile capita con le stringhe:

>>> def up(st):
...   return st.upper()
...
>>> st = 'ciao!'
>>> us = up(st)
>>> st
'ciao!'
>>> us
'CIAO!'

ho barato: ho applicato a st il metodo upper() che non la modifica ma ne crea una copia. Se modifico st nella funzione ottengo:

>>> def upm(st):
...   st = st.upper()
...   print("dentro", st)
...   return st
...
>>> st
'ciao!'
>>> us = upm(st)
dentro CIAO!
>>> us
'CIAO'
>>> st
'ciao!'

Tutto come previsto.

E le liste? In Python le liste vengono usate (anche?) al posto degli arrays; e funzionano bene.

Ecco lsquad(), restituisce la lista dei quadrati degli elementi della lista passata.

>>> def lsquad(ls):
...   ls = [ls[n] * ls[n] for n in range (len(ls))]
...   return ls
...
>>> lorig = [1, 2, 3, 4]
>>> lq = lsquad(lorig)
>>> lq
[1, 4, 9, 16]
>>> lorig
[1, 2, 3, 4]

OK, ma io che sono vecchio, più vecchio della list comprehension a  volte  spesso scrivo così:

>>> def lsfq(ls):
...   for n in range(len(ls)):
...     ls[n] = ls[n] * ls[n]
...   return ls
...
>>> lorig
[1, 2, 3, 4]
>>> lq = lsfq(lorig)
>>> lq
[1, 4, 9, 16]
>>> lorig
[1, 4, 9, 16]

OOPS! con il ciclo for la stringa passata è stata aggiornata!

E chiamate successive producono questo effetto:

>>> lq = lsfq(lorig)
>>> lorig
[1, 16, 81, 256]
>>> lq = lsfq(lorig)
>>> lorig
[1, 256, 6561, 65536]

Mi suggeriscono (tra le altre cose) questa variante, con costruzione di una nuova lista (rl):

def lstq(ls):
  rl = []
  for n in ls:
    rl.append(n * n)
  return rl

È OK ma sono sempre per la list comprehension. Forse solo questione di gusti.
CMQ, panico? No, c’è tutto scritto nella documentazione. E adesso anche qui.

E poi, se vi ricordate anche il C… (quella cosa del puntatore all’elemento iniziale dell’array, o ricordo male?) 😉

Oh! post è già stato aggiornato (due volte) in bozza prima ancora di essere pubblicato nel blog. E chissà se adesso è OK.

👽

Posta un commento o usa questo indirizzo per il trackback.

Rispondi

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo di WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione /  Modifica )

Google photo

Stai commentando usando il tuo account Google. Chiudi sessione /  Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione /  Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione /  Modifica )

Connessione a %s...

Questo sito utilizza Akismet per ridurre lo spam. Scopri come vengono elaborati i dati derivati dai commenti.

%d blogger hanno fatto clic su Mi Piace per questo: