Difference between revisions of "Esempi didattici in Python"
(Created page with "Questa pagina contiene alcuni esempi di codice Python usati durante le lezioni (e non solo) === Divisori === Esempio sui divisori. Il primo programma ha uno stile Pascal o C:...") |
m |
||
(6 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
− | Questa pagina contiene alcuni esempi di codice Python | + | Questa pagina contiene alcuni esempi didattici di codice Python |
=== Divisori === | === Divisori === | ||
Esempio sui divisori. Il primo programma ha uno stile Pascal o C: | Esempio sui divisori. Il primo programma ha uno stile Pascal o C: | ||
− | + | <source lang=python> | |
− | < | ||
#!/usr/bin/env python3 | #!/usr/bin/env python3 | ||
Line 34: | Line 33: | ||
print("i divisori di ", n, "sono", divisori(n)) | print("i divisori di ", n, "sono", divisori(n)) | ||
print("i divisori primi di ", n, "sono", divisoriprimi(n)) | print("i divisori primi di ", n, "sono", divisoriprimi(n)) | ||
− | </ | + | </source> |
Ma il Python ha anche il tipo insieme (set) che e' meglio indicato per questo esempio: | Ma il Python ha anche il tipo insieme (set) che e' meglio indicato per questo esempio: | ||
− | < | + | |
+ | <source lang=python> | ||
#!/usr/bin/env python3 | #!/usr/bin/env python3 | ||
Line 67: | Line 67: | ||
print("i divisori di ", n, "sono", divisori(n)) | print("i divisori di ", n, "sono", divisori(n)) | ||
print("i divisori primi di ", n, "sono", divisoriprimi(n)) | print("i divisori primi di ", n, "sono", divisoriprimi(n)) | ||
− | </ | + | </source> |
Lo stesso esempio con la Set Comprehension (come si traduce? si traduce?): | Lo stesso esempio con la Set Comprehension (come si traduce? si traduce?): | ||
− | < | + | |
+ | <source lang=python> | ||
#!/usr/bin/env python3 | #!/usr/bin/env python3 | ||
Line 89: | Line 90: | ||
print("i divisori di ", n, "sono", divisori(n)) | print("i divisori di ", n, "sono", divisori(n)) | ||
print("i divisori primi di ", n, "sono", divisoriprimi(n)) | print("i divisori primi di ", n, "sono", divisoriprimi(n)) | ||
− | </ | + | </source> |
Il primo e' piu' ''algoritmico, passo a passo'', ma anche piu' contorto. Il secondo e' piu' elegante ma puo' apparire ''magico-misterioso''. | Il primo e' piu' ''algoritmico, passo a passo'', ma anche piu' contorto. Il secondo e' piu' elegante ma puo' apparire ''magico-misterioso''. | ||
Line 96: | Line 97: | ||
Il metodo migliore per calcolare il massimo comun divisore e' l'algoritmo di Euclide: | Il metodo migliore per calcolare il massimo comun divisore e' l'algoritmo di Euclide: | ||
− | < | + | <source lang=python> |
def gcd(x, y): | def gcd(x, y): | ||
while True: | while True: | ||
Line 107: | Line 108: | ||
def lcm(x, y): | def lcm(x, y): | ||
return x * y // gcd(x, y) | return x * y // gcd(x, y) | ||
− | </ | + | </source> |
=== Coda/Pila e programmazione a oggetti === | === Coda/Pila e programmazione a oggetti === | ||
Line 168: | Line 169: | ||
Ma le code e le pile possono venir viste anche come classi derivate della classe liste. | Ma le code e le pile possono venir viste anche come classi derivate della classe liste. | ||
La prima versione chiama i metodi della classe lista esplicitamente: | La prima versione chiama i metodi della classe lista esplicitamente: | ||
− | < | + | <source lang=python> |
class queue(list): | class queue(list): | ||
def __init__(self): | def __init__(self): | ||
Line 194: | Line 195: | ||
def empty(self): | def empty(self): | ||
return not list(self) | return not list(self) | ||
− | </ | + | </source> |
Questa versione e' per me elegante perche' tutte le funzioni vengono richiamate in modo uniforme. L'unico neo e' la necessita' di usare nomi di classi come prefisso dei metodi (di solito si usano i nomi degli oggetti e si omette self come parametro). | Questa versione e' per me elegante perche' tutte le funzioni vengono richiamate in modo uniforme. L'unico neo e' la necessita' di usare nomi di classi come prefisso dei metodi (di solito si usano i nomi degli oggetti e si omette self come parametro). | ||
La seconda versione usa la ereditarieta': i metodi vengono richiamati semplicemente per nome, assumendo che si faccia riferimento alla prima definizione utile presente in una delle classi "ave" (anchestor). | La seconda versione usa la ereditarieta': i metodi vengono richiamati semplicemente per nome, assumendo che si faccia riferimento alla prima definizione utile presente in una delle classi "ave" (anchestor). | ||
− | < | + | <source lang=python> |
class queue(list): | class queue(list): | ||
def __init__(self): | def __init__(self): | ||
Line 225: | Line 226: | ||
def empty(self): | def empty(self): | ||
return not self | return not self | ||
− | </ | + | </source> |
Purtroppo si rende necessario talvolta l'uso di ''super'' per fare riferimento a metodi con lo stesso nome, | Purtroppo si rende necessario talvolta l'uso di ''super'' per fare riferimento a metodi con lo stesso nome, | ||
--> | --> | ||
Line 234: | Line 235: | ||
Puo' essere interessante per introdurre gli insiemi in Python. La definizione appare naturale e descrittiva. | Puo' essere interessante per introdurre gli insiemi in Python. La definizione appare naturale e descrittiva. | ||
− | < | + | <source lang=python> |
def sieve(n): | def sieve(n): | ||
sv={x for x in range(1,n)} | sv={x for x in range(1,n)} | ||
Line 241: | Line 242: | ||
sv -= {x for x in range(2*i,n,i)} | sv -= {x for x in range(2*i,n,i)} | ||
return [x for x in range(n) if x in sv] | return [x for x in range(n) if x in sv] | ||
− | </ | + | </source> |
=== Ordinamento === | === Ordinamento === | ||
Line 249: | Line 250: | ||
Sort per selezione: | Sort per selezione: | ||
− | < | + | <source lang=python> |
def selection_sort(v): | def selection_sort(v): | ||
for i in range(len(v)): | for i in range(len(v)): | ||
Line 255: | Line 256: | ||
if v[j] < v[i]: | if v[j] < v[i]: | ||
v[i],v[j]=v[j],v[i] | v[i],v[j]=v[j],v[i] | ||
− | </ | + | </source> |
Sort per inserzione: | Sort per inserzione: | ||
− | < | + | <source lang=python> |
def insertion_sort(v): | def insertion_sort(v): | ||
for i in range(1,len(v)): | for i in range(1,len(v)): | ||
Line 264: | Line 265: | ||
if v[j] > v[i]: | if v[j] > v[i]: | ||
v.insert(j, v.pop(i)) | v.insert(j, v.pop(i)) | ||
− | </ | + | </source> |
Bubblesort: | Bubblesort: | ||
− | < | + | <source lang=python> |
def bubblesort(v): | def bubblesort(v): | ||
for i in range(1,len(v)): | for i in range(1,len(v)): | ||
Line 273: | Line 274: | ||
if v[j+1] < v[j]: | if v[j+1] < v[j]: | ||
v[j+1],v[j]=v[j],v[j+1] | v[j+1],v[j]=v[j],v[j+1] | ||
− | </ | + | </source> |
Una implementazione del quicksort molto compatta e elegante si ottiene con la List Comprehension (copia il vettore come il metodo standard ''sorted''): | Una implementazione del quicksort molto compatta e elegante si ottiene con la List Comprehension (copia il vettore come il metodo standard ''sorted''): | ||
− | < | + | <source lang=python> |
def rqsorted(v): | def rqsorted(v): | ||
if v: | if v: | ||
Line 285: | Line 286: | ||
else: | else: | ||
return [] | return [] | ||
− | </ | + | </source> |
Il mergesort e' un po' piu' macchinoso. La prima versione prevede l'ordinamento del vettore stesso, vengono copiati temporaneamente i vettori parziali e poi le sequenze vengono reinserite nel vettore originale: | Il mergesort e' un po' piu' macchinoso. La prima versione prevede l'ordinamento del vettore stesso, vengono copiati temporaneamente i vettori parziali e poi le sequenze vengono reinserite nel vettore originale: | ||
− | < | + | <source lang=python> |
def merge(v1,v2): | def merge(v1,v2): | ||
v=[] | v=[] | ||
Line 309: | Line 310: | ||
v[i:i+2*ls]=merge(v[i:i+ls],v[i+ls:i+2*ls]) | v[i:i+2*ls]=merge(v[i:i+ls],v[i+ls:i+2*ls]) | ||
ls *= 2 | ls *= 2 | ||
− | </ | + | </source> |
La seconda versione del mergesort copia il vettore. Anche la funzione rmerge e' ricorsiva. | La seconda versione del mergesort copia il vettore. Anche la funzione rmerge e' ricorsiva. | ||
− | < | + | <source lang=python> |
def rmerge(v1,v2): | def rmerge(v1,v2): | ||
if not v1: | if not v1: | ||
Line 329: | Line 330: | ||
else: | else: | ||
return rmerge(rmergesorted(v[:half]),rmergesorted(v[half:])) | return rmerge(rmergesorted(v[:half]),rmergesorted(v[half:])) | ||
− | </ | + | </source> |
Le definizioni delle funzioni ''merge'' e ''rmerge'' non sono state inserite nella definizione delle funzioni ''mergesort'' e ''rmergesorted'' (rispettivamente) perche' hanno una funzionalita' specifica di fusione di vettori ordinati e possono essere usate anche indipendentemente dal mergesort. | Le definizioni delle funzioni ''merge'' e ''rmerge'' non sono state inserite nella definizione delle funzioni ''mergesort'' e ''rmergesorted'' (rispettivamente) perche' hanno una funzionalita' specifica di fusione di vettori ordinati e possono essere usate anche indipendentemente dal mergesort. |
Latest revision as of 10:48, 28 October 2019
Questa pagina contiene alcuni esempi didattici di codice Python
Divisori
Esempio sui divisori. Il primo programma ha uno stile Pascal o C:
#!/usr/bin/env python3
def divisori(x):
s=[]
for i in range(2,x):
if x%i == 0:
s.append(i)
return s;
def primo(x):
if divisori(x):
return False
else:
return True
def divisoriprimi(x):
s=[]
for i in divisori(x):
if (primo(i)):
s.append(i)
return s
if __name__ == '__main__':
n=int(input("dammi n "))
if primo(n):
print(n ,"e' primo")
else:
print("i divisori di ", n, "sono", divisori(n))
print("i divisori primi di ", n, "sono", divisoriprimi(n))
Ma il Python ha anche il tipo insieme (set) che e' meglio indicato per questo esempio:
#!/usr/bin/env python3
def divisori(x):
s=set()
for i in range(2,x):
if x%i == 0:
s.add(i)
return s;
def primo(x):
if divisori(x):
return False
else:
return True
def divisoriprimi(x):
s=set()
for i in divisori(x):
if (primo(i)):
s.add(i)
return s
if __name__ == '__main__':
n=int(input("dammi n "))
if primo(n):
print(n ,"e' primo")
else:
print("i divisori di ", n, "sono", divisori(n))
print("i divisori primi di ", n, "sono", divisoriprimi(n))
Lo stesso esempio con la Set Comprehension (come si traduce? si traduce?):
#!/usr/bin/env python3
def divisori(x):
return {y for y in range(2,x) if x%y == 0}
def primo(x):
return not divisori(x)
def divisoriprimi(x):
return {y for y in divisori(x) if primo(y)}
if __name__ == '__main__':
n=int(input("dammi n "))
if primo(n):
print(n ,"e' primo")
else:
print("i divisori di ", n, "sono", divisori(n))
print("i divisori primi di ", n, "sono", divisoriprimi(n))
Il primo e' piu' algoritmico, passo a passo, ma anche piu' contorto. Il secondo e' piu' elegante ma puo' apparire magico-misterioso.
Fattorizzazione, mcm e MCD
Il metodo migliore per calcolare il massimo comun divisore e' l'algoritmo di Euclide:
def gcd(x, y):
while True:
if x < y:
x, y = y, x
x -= y
if x == 0:
return y
def lcm(x, y):
return x * y // gcd(x, y)
Coda/Pila e programmazione a oggetti
Le code e le pile (queue e stack) possono essere implementate a partire dalle liste. Le funzioni enqueue/dequeue per le code e push/pop per le pile possono essere implementate cosi':
def enqueue(s,x):
s.append(x)
def dequeue(s):
return s.pop(0)
def push(s,x):
s.append(x)
def pop(s):
return s.pop()
Passando alla programmazione a oggetti, la versione migliore e' quella con un attributo nascosto "lista", perche' una coda ha una lista, non è una lista
class queue:
def __init__(self):
self._list=[]
def enqueue(self, x):
self._list.append(x)
def dequeue(self):
return self._list.pop(0)
def empty(self):
return not self._list
def head(self):
return self._list[0]
def __str__(self):
return str(self._list)
class stack:
def __init__(self):
self._list=[]
def push(self, x):
self._list.append(x)
def pop(self):
return self._list.pop()
def empty(self):
return not self._list
def __str__(self):
return str(self._list)
Il setaccio di Eratostene
Ai miei tempi si chiamava crivello!
Puo' essere interessante per introdurre gli insiemi in Python. La definizione appare naturale e descrittiva.
def sieve(n):
sv={x for x in range(1,n)}
for i in range(2,n//2):
if i in sv:
sv -= {x for x in range(2*i,n,i)}
return [x for x in range(n) if x in sv]
Ordinamento
Ecco una carrellata di funzioni per l'ordinamento... Le prime sono funzioni per l'ordinamento di vettori/liste sul posto, modificando la sequenza degli elementi.
Sort per selezione:
def selection_sort(v):
for i in range(len(v)):
for j in range(i+1,len(v)):
if v[j] < v[i]:
v[i],v[j]=v[j],v[i]
Sort per inserzione:
def insertion_sort(v):
for i in range(1,len(v)):
for j in range(i):
if v[j] > v[i]:
v.insert(j, v.pop(i))
Bubblesort:
def bubblesort(v):
for i in range(1,len(v)):
for j in range(len(v)-i):
if v[j+1] < v[j]:
v[j+1],v[j]=v[j],v[j+1]
Una implementazione del quicksort molto compatta e elegante si ottiene con la List Comprehension (copia il vettore come il metodo standard sorted):
def rqsorted(v):
if v:
pivot=v[0]
lesser=[x for x in v[1:] if x <= pivot]
greater=[x for x in v[1:] if x > pivot]
return rqsorted(lesser) + [pivot] + rqsorted(greater)
else:
return []
Il mergesort e' un po' piu' macchinoso. La prima versione prevede l'ordinamento del vettore stesso, vengono copiati temporaneamente i vettori parziali e poi le sequenze vengono reinserite nel vettore originale:
def merge(v1,v2):
v=[]
while True:
if not v1:
return v+v2
elif not v2:
return v+v1
else:
if v1[0] < v2[0]:
v.append(v1.pop(0))
else:
v.append(v2.pop(0))
def mergesort(v):
lv=len(v)
ls=1;
while v[ls:]:
for i in range(0,lv,2*ls):
v[i:i+2*ls]=merge(v[i:i+ls],v[i+ls:i+2*ls])
ls *= 2
La seconda versione del mergesort copia il vettore. Anche la funzione rmerge e' ricorsiva.
def rmerge(v1,v2):
if not v1:
return v2
elif not v2:
return v1
elif v1[0] < v2[0]:
return v1[0:1]+rmerge(v1[1:],v2)
else:
return v2[0:1]+rmerge(v1,v2[1:])
def rmergesorted(v):
half=len(v)//2
if half == 0:
return v
else:
return rmerge(rmergesorted(v[:half]),rmergesorted(v[half:]))
Le definizioni delle funzioni merge e rmerge non sono state inserite nella definizione delle funzioni mergesort e rmergesorted (rispettivamente) perche' hanno una funzionalita' specifica di fusione di vettori ordinati e possono essere usate anche indipendentemente dal mergesort.