Programmazione in Python

Guida completa alla programmazione funzionale e alle strutture dati

Impara Python dalle basi: dalla sintassi fondamentale alle strutture dati avanzate. Questa guida ti accompagnerà nel mondo della programmazione funzionale con esempi pratici e spiegazioni dettagliate.

Concetti Base
Strumenti Pratici
Strutture Dati
Esempi Pratici

Introduzione a Python

Scopri le basi della programmazione funzionale con Python

Obiettivi del Corso

Questo corso introduce la programmazione funzionale e la programmazione in Python, fornendo una base solida per sviluppatori di tutti i livelli.

Perché Python?

Python non è un linguaggio principalmente funzionale, ma è un linguaggio multiparadigma che supporta programmazione procedurale, orientata agli oggetti e funzionale. Esistono linguaggi principalmente funzionali (OCaml, Haskell, F#), ma abbiamo scelto Python per la sua diffusione e praticità.

Vantaggi di Python:
  • Relativamente facile da imparare
  • Interfacciamento con librerie C ad alte prestazioni
  • Ecosistema enorme di librerie disponibili
  • Supporto per diversi paradigmi di programmazione

Perché la Programmazione Funzionale?

  • Base matematica: Fondata sul lambda calcolo
  • Paradigma diverso: Insegna approcci alternativi alla risoluzione dei problemi
  • Semplicità: Spesso porta a soluzioni più eleganti
  • Parallelizzazione: Si presta meglio all'esecuzione parallela automatica

Elementi della Programmazione Funzionale

  • Composizione di funzioni: I programmi sono combinazioni di funzioni
  • Funzioni come oggetti: Possono essere passate come parametri e ritornate
  • Immutabilità: I dati non vengono modificati, ma sostituiti con nuovi dati
  • Lazy evaluation: Calcoli eseguiti solo quando necessari
Immutabilità in Python: Python ha sia dati immutabili (tipi primitivi, stringhe, tuple) che dati mutabili (liste, insiemi, dizionari).

Storia di Python

Le origini e l'evoluzione del linguaggio

Origini e Sviluppo

  • Creatore: Guido van Rossum, programmatore olandese
  • Nome: Deriva da "Monty Python's Flying Circus"
  • Primo rilascio: 1991
  • Versione 2.0: 2000
  • Versione 3.0: 2008
Importante: Python 3 è molto diverso da Python 2 e non è backward-compatible. Il supporto per Python 2 è terminato il 1° gennaio 2020.

Strumenti di Sviluppo

Gli ambienti per programmare in Python

Anaconda Distribution

Nel laboratorio utilizziamo Anaconda3, che include:

  • Python 3.7.3 (o versioni successive)
  • Jupyter Notebooks
  • Spyder IDE
  • Numerose librerie pre-installate
Avvio di Anaconda Navigator
/opt/anaconda3/bin/anaconda-navigator

Jupyter Notebook

Jupyter Notebook è un'applicazione web interattiva che permette di creare e condividere documenti contenenti codice, equazioni, visualizzazioni e testo narrativo.

Caratteristiche Principali

  • File .ipynb: Contengono testo e codice eseguibile
  • Celle: Possono essere di tipo Markdown (testo) o Code (codice Python)
  • Architettura client-server: Funziona nel browser web
  • Kernel condiviso: Tutte le celle condividono lo stesso spazio di memoria
Shortcuts Utili:
  • Ctrl+Enter: Esegue la cella corrente
  • Enter: Entra in modalità Edit
  • Esc: Entra in modalità Command
Attenzione: In modalità Command sono attivi molti shortcuts. Evita di digitare per non modificare accidentalmente le celle.

Spyder IDE

Spyder è un ambiente di sviluppo integrato per Python, particolarmente adatto per sviluppo scientifico e data analysis.

Interfaccia Spyder

  • Pannello Editor: A sinistra, per scrivere codice
  • Console IPython: In basso a destra, per esecuzione interattiva
  • Pannello ausiliario: In alto a destra, con diverse tab
Shortcuts Spyder
Shortcut Funzione
F5 Esegue tutto il file
Ctrl+Enter Esegue la cella corrente
F9 Esegue la riga corrente
Ctrl+C Interrompe l'esecuzione

Strutture Dati in Python

Le collezioni di dati e le loro caratteristiche

Sequenze

Le sequenze sono collezioni ordinate di elementi. Python offre diversi tipi di sequenze, ognuna con caratteristiche specifiche.

Accesso agli Elementi

L'accesso agli elementi avviene tramite indicizzazione con parentesi quadre:

aSeq[i]  # Ritorna l'i-esimo elemento della sequenza
Indicizzazione: Gli indici iniziano da 0. Gli indici negativi partono dalla fine: aSeq[-1] è l'ultimo elemento.
Esempi di Indicizzazione
ls = [1, 2, 3, 4]
# Elemento 1: indice 0 o -4
# Elemento 2: indice 1 o -3
# Elemento 3: indice 2 o -2
# Elemento 4: indice 3 o -1

Operazioni Comuni

Operazione Sintassi Descrizione
Concatenazione seq1 + seq2 Unisce due sequenze dello stesso tipo
Ripetizione seq * n Ripete la sequenza n volte
Appartenenza x in seq Verifica se x è nella sequenza
Lunghezza len(seq) Ritorna il numero di elementi

Funzioni Utili

  • min(seq) e max(seq): Trovano minimo e massimo
  • seq.index(x): Ritorna l'indice della prima occorrenza di x
  • seq.count(x): Conta le occorrenze di x

Stringhe

Le stringhe sono sequenze di caratteri. In Python non esiste il tipo "carattere" - esistono solo stringhe di lunghezza 1.

Immutabilità: Le stringhe sono immutabili - non possono essere modificate dopo la creazione.

Tipi di Letterali Stringa

Tipo Sintassi Uso
Apici singoli 'stringa' Uso generale
Apici doppi "stringa" Quando serve apice singolo interno
Multi-linea '''stringa''' Testo su più righe
Raw string r'path\to\file' Evita interpretazione caratteri escape
f-string f'Ciao {nome}!' Interpolazione di variabili

Caratteri Speciali

  • \n: Nuova riga
  • \t: Tab
  • \\: Backslash letterale
  • \' e \": Apici letterali
Esempi di Stringhe
# Stringhe multi-linea
testo = '''Questa è una
    stringa
su tre righe'''

# Raw string
percorso = r'C:\Users\nome\file.txt'

# f-string
nome = "Mario"
messaggio = f'Ciao {nome}!'

# Concatenazione automatica
risultato = "prima" "seconda"  # "primaseconda"
Concatenazione automatica: Stringhe consecutive vengono automaticamente concatenate in Python.

Slicing

Lo slicing permette di estrarre porzioni di sequenze creando nuove sequenze.

Sintassi Completa

sequenza[inizio:fine:passo]
  • inizio: Indice di partenza (incluso)
  • fine: Indice di fine (escluso)
  • passo: Incremento (default: 1)
Esempi di Slicing
s = "abcdefg"

# Esempi base
s[1:4]     # "bcd"
s[:3]      # "abc" (dall'inizio)
s[2:]      # "cdefg" (fino alla fine)
s[:]       # "abcdefg" (copia completa)

# Con passo
s[::2]     # "aceg" (elementi pari)
s[1::2]    # "bdf" (elementi dispari)

# Slicing inverso
s[::-1]    # "gfedcba" (stringa invertita)
s[5:1:-1]  # "fedc" (da destra a sinistra)
Slicing crea nuove sequenze: L'operazione di slicing genera sempre una nuova sequenza, non modifica quella originale.

Liste

Le liste sono sequenze mutabili che possono contenere elementi di qualsiasi tipo.

Mutabilità: Le liste possono essere modificate dopo la creazione - si possono aggiungere, rimuovere o modificare elementi.

Creazione di Liste

# Lista con elementi
numeri = [1, 2, 3, 4, 5]

# Lista mista (sconsigliata)
mista = [1, "due", 3.0, [4, 5]]

# Lista vuota
vuota = []

# Da stringa
caratteri = list("python")  # ['p', 'y', 't', 'h', 'o', 'n']

Metodi Principali

Metodo Descrizione Esempio
append(x) Aggiunge elemento alla fine lista.append(6)
extend(seq) Aggiunge tutti gli elementi di seq lista.extend([7, 8])
insert(i, x) Inserisce elemento alla posizione i lista.insert(0, 0)
remove(x) Rimuove prima occorrenza di x lista.remove(3)
pop(i) Rimuove e ritorna elemento all'indice i elemento = lista.pop()
clear() Rimuove tutti gli elementi lista.clear()
sort() Ordina la lista lista.sort()
reverse() Inverte l'ordine lista.reverse()

Unpacking con Asterisco

Esempi di Unpacking
numeri = [1, 2, 3, 4, 5]

# Unpacking base
primo, secondo = [1, 2]

# Con asterisco
primo, *resto = numeri          # primo=1, resto=[2,3,4,5]
*inizio, ultimo = numeri        # inizio=[1,2,3,4], ultimo=5
primo, *mezzo, ultimo = numeri  # primo=1, mezzo=[2,3,4], ultimo=5

Assegnamento a Slice

Le liste supportano l'assegnamento diretto a slice, permettendo di modificare porzioni della lista:

lista = [1, 2, 3, 4, 5]

# Sostituisce elementi
lista[1:4] = [7, 8]      # [1, 7, 8, 5]

# Cambia lunghezza
lista[2:] = [9, 10, 11]  # [1, 7, 9, 10, 11]

# Slice esteso (passo > 1)
lista[::2] = [0, 0, 0]   # Sostituisce elementi a posizioni pari
Attenzione ai riferimenti: Assegnare una lista a un'altra variabile crea un riferimento, non una copia. Usa lista[:] o lista.copy() per creare una copia.

Tuple

Le tuple sono sequenze immutabili, spesso utilizzate per dati eterogenei.

Immutabilità: Le tuple non possono essere modificate dopo la creazione, ma possono contenere elementi mutabili.

Creazione di Tuple

# Con parentesi
coordinate = (10, 20)
persona = ("Mario", 30, "Roma")

# Senza parentesi
punto = 1, 2, 3

# Tupla vuota
vuota = ()

# Tupla con un elemento (nota la virgola!)
singleton = (42,)

# Da lista
da_lista = tuple([1, 2, 3])
Tupla singleton: Per creare una tupla con un elemento, serve la virgola finale: (42,). Altrimenti (42) è solo un numero tra parentesi.

Utilizzo delle Tuple

  • Coordinate: (x, y, z)
  • Dati eterogenei: (nome, età, città)
  • Chiavi di dizionario: Se contengono solo dati immutabili
  • Valori di ritorno multipli: return nome, età

Set

I set sono collezioni non ordinate di elementi unici, utili per operazioni insiemistiche.

Creazione di Set

# Con parentesi graffe
numeri = {1, 2, 3, 4, 5}

# Rimuove duplicati automaticamente
unici = {1, 2, 3, 2, 3, 1}  # {1, 2, 3}

# Set vuoto (non {})
vuoto = set()

# Da lista
da_lista = set([1, 2, 2, 3])  # {1, 2, 3}
Set vuoto: {} crea un dizionario vuoto, non un set. Per un set vuoto usa set().

Operazioni Insiemistiche

Operazione Operatore Metodo Descrizione
Unione | union() Elementi in almeno uno dei set
Intersezione & intersection() Elementi in entrambi i set
Differenza - difference() Elementi nel primo ma non nel secondo
Diff. simmetrica ^ symmetric_difference() Elementi in uno solo dei due set
Esempi di Operazioni su Set
set1 = {1, 2, 3, 4}
set2 = {3, 4, 5, 6}

print(set1 | set2)  # {1, 2, 3, 4, 5, 6} - Unione
print(set1 & set2)  # {3, 4} - Intersezione
print(set1 - set2)  # {1, 2} - Differenza
print(set1 ^ set2)  # {1, 2, 5, 6} - Differenza simmetrica

Dizionari

I dizionari sono collezioni di coppie chiave-valore, ottimizzate per l'accesso rapido tramite chiave.

Chiavi hashable: Le chiavi devono essere immutabili e contenere solo oggetti immutabili (hashable).

Creazione di Dizionari

# Sintassi base
studente = {
    "nome": "Mario",
    "età": 20,
    "corso": "Informatica"
}

# Dizionario vuoto
vuoto = {}

# Con funzione dict()
da_coppie = dict([('a', 1), ('b', 2)])
con_keywords = dict(nome="Mario", età=20)

Accesso e Modifica

# Accesso
print(studente["nome"])        # Mario
print(studente.get("voto", 0)) # 0 (default se chiave non esiste)

# Modifica
studente["voto"] = 28
studente["età"] = 21

# Verifica esistenza
if "nome" in studente:
    print("Nome presente")

Metodi Principali

Metodo Descrizione Esempio
keys() Ritorna le chiavi list(dict.keys())
values() Ritorna i valori list(dict.values())
items() Ritorna coppie chiave-valore list(dict.items())
get(key, default) Accesso sicuro con default dict.get("chiave", "N/A")
pop(key) Rimuove e ritorna valore valore = dict.pop("chiave")
update(other) Aggiorna con altro dizionario dict.update({"nuovo": "valore"})

Iterazione

Modi di Iterare sui Dizionari
# Sulle chiavi (default)
for chiave in dizionario:
    print(chiave)

# Su chiavi e valori
for chiave, valore in dizionario.items():
    print(f"{chiave}: {valore}")

# Solo sui valori
for valore in dizionario.values():
    print(valore)
Concetto di Hashable: Un oggetto è hashable se è immutabile e contiene solo oggetti immutabili. Le tuple sono hashable solo se tutti i loro elementi lo sono.

Funzioni di Conversione

Le funzioni di conversione creano nuovi oggetti del tipo desiderato senza modificare quelli originali.

Importante: Le funzioni di conversione non modificano l'oggetto originale, ma creano un nuovo oggetto del tipo richiesto.

Conversioni Principali

Funzione Da A Esempio
int() str, float, bool int int("42")42
float() str, int, bool float float("3.14")3.14
str() qualsiasi str str([1,2,3])"[1, 2, 3]"
list() str, tuple, set list list("abc")['a', 'b', 'c']
tuple() str, list, set tuple tuple([1,2,3])(1, 2, 3)
set() str, list, tuple set set([1,1,2]){1, 2}
dict() liste di coppie dict dict([('a',1), ('b',2)])

Conversioni Speciali

Funzione Descrizione Esempio
ord() Carattere → codice ASCII ord('A')65
chr() Codice ASCII → carattere chr(65)'A'
hex() Intero → esadecimale hex(255)'0xff'
bin() Intero → binario bin(8)'0b1000'
oct() Intero → ottale oct(8)'0o10'
Esempi di Conversioni
# Conversioni numeriche
print(float(True))    # 1.0
print(int("321") + 4) # 325

# Conversioni di strutture dati
print(list({'a': 1, 'b': 2}))  # ['a', 'b'] (solo chiavi)
print(list("PYTHON"))          # ['P', 'Y', 'T', 'H', 'O', 'N']

# Conversioni speciali
print(hex(20))  # 0x14
print(chr(69))  # E

Conclusioni

Il tuo percorso di apprendimento Python inizia qui

Complimenti!

Hai completato la guida introduttiva a Python e alle sue strutture dati. Ora hai le basi per iniziare a programmare in Python con fiducia!

Prossimi Passi

Pratica

Sperimenta con gli esercizi e i file Python forniti

Strumenti

Familiarizza con Jupyter Notebooks e Spyder

Funzionale

Approfondisci la programmazione funzionale

Librerie

Esplora le librerie Python per i tuoi interessi

Risorse Aggiuntive

  • "Programmare con Python Guida completa" di Marco Buttu
  • "Functional Python Programming" di Steven Lott
  • Documentazione ufficiale Python docs.python.org