Usare gli Jupyter Notebook¶
I notebook Jupyter sono uno strumento molto utile per scrivere relazioni scientifiche, esplorare dati e documentare codice in modo ordinato. Sono un esempio di "literate programming", ovvero un modo di scrivere codice che è anche leggibile come testo, con spiegazioni e commenti.
In questo notebook vedremo i punti essenziali per usarli bene:
- struttura a celle (testo + codice)
- ruolo del kernel e della memoria
- errori comuni di esecuzione fuori ordine
- basi di Markdown e LaTeX per scrivere relazioni leggibili
- primo uso di NumPy per leggere/salvare dati
Per un'introduzione più avanzata a Jupyter/JupyterLab (in inglese):
Nota su questa versione¶
Questo notebook è stato aggiornato rispetto alla versione vista in aula.
Modifiche principali:
- Aggiunte risorse di approfondimento.
- Chiarite alcune parti operative che in aula sono state fatte dal vivo.
- Inseriti collegamenti con la lezione del 04.03.2026.
- Le parti su funzioni e liste sono state spostate in un notebook dedicato.
I fondamentali¶
- Ogni notebook esegue il codice tramite un interprete chiamato kernel. Il kernel è un processo che gira in background e mantiene la memoria di tutte le variabili e funzioni che vengono definite durante l'esecuzione del notebook. Su vscode questo è visibile in alto a destra, dove è indicato il nome del kernel (ad esempio "Python 3") mentre in jupyter lab è indicato con un pallino colorato. Il kernel viene eseguito nella finestra di terminal che si apre quando si avvia il notebook. Pertanto, chiudere la finestra di terminal chiude anche il kernel e resetta la memoria.
- Le celle si eseguono con
Shift+Invioo con il pulsante Run. - La memoria appartiene al kernel ed è condivisa da tutte le celle. Se una variabile viene definite in una cella, è accessibile da tutte le altre celle che vengono eseguite dopo.
- Per resettare la memoria bisogna riavviare il kernel.
- Il numero tra parentesi quadre a sinistra (
[ ]) indica l'ordine di esecuzione, non la posizione visiva della cella.
Attenzione¶
L'ordine di esecuzione può non coincidere con l'ordine delle celle nel notebook: questo è uno dei motivi principali di errori apparentemente "misteriosi".
from math import * #questo importa tutte le funzioni matematiche
a = 10 # salva il valore 10 in una variabile a, equivalente al nostro pseudocodice a <- 10.
#<--- fate molta attenzione al numero qui a sinistra, che è l'ordine di esecuzione delle celle!
# Se eseguite prima la cella successiva e poi questa, il valore da `a` sarà 20 e non 10.
print(a)
10
a = 20
# Allo stesso modo, se eseguiamo più volte una singola cella, il suo effetto si ripete più volte.
# Ogni volta che eseguiamo questa cella, `a` viene raddoppiato. Se la eseguiamo una volta, `a` diventa 40, se la eseguiamo una seconda volta `a` diventa 80 e così via.
a = 2*a
print(a)
40
Se ora definiamo una variabile b = a*2, poi commentiamo o cancelliamo la cella, b può restare comunque disponibile perché è già stata salvata nella memoria del kernel.
b = a*2
Prova pratica:
- Esegui la cella che definisce
b = a*2. - Commenta o cancella quella cella.
- Esegui la cella successiva con
print(b).
Se il kernel non è stato riavviato, il valore viene ancora stampato.
print(b)
80
La stessa cosa succede se sposti la cella con la definizione di una variabile dopo la cella che la usa: quello che conta è l'ordine di esecuzione mostrato a sinistra, non l'ordine visivo nel notebook.
# <--- il numero qui a fianco è l'ordine di esecuzione, ed è la cosa da considerare.
# ridefiniamo la variabile a
a = b
Riesegui ora la cella in cui compare print(a): il numero di esecuzione cambierà e il risultato potrà essere diverso da quanto ti aspetti leggendo il notebook dall'alto verso il basso.
Questa particolarità rende i notebook rende piuttosto pericolosi, per cui è meglio tenerla presente e sapere come rimediare. Il modo migliore è quello di far ripartire il kernel ogni tanto, in modo da cancellare le variabili "spurie" rimaste in memoria. Quando salvate un notebook su file, lo stato della memoria non verrà salvato e quindi l'esecuzione metterà in luce gli stessi problemi identificabili tramite il reset del kernel.
Per evitare confusione, quando hai raggiunto un punto in cui non sei più sicuro di quali variabili siano ancora definite o di quale sia il loro valore, fai Kernel -> Restart e riesegui le celle in ordine per assicurarti che tutto sia definito come ti aspetti.
Se una variabile non è più definita, Python genera un errore NameError.
print(b)
80
Esercizio - Persistenza delle variabili nel kernel¶
Nella cella seguente:
- Definisci una variabile
variabilee assegnale un valore. - Esegui la cella.
- Commenta o cancella la cella.
- Nella cella successiva prova a stampare
variabile.
Domanda: cosa succede e perché?
# Definisci qui la variabile richiesta dall'esercizio
variabile = ...
# Prova a stampare la variabile dopo aver cancellato/commentato la cella precedente
Attenzione: nomi che sovrascrivono funzioni¶
In Python puoi assegnare una variabile con lo stesso nome di una funzione o di una parola chiave (keyword) già esistente. Questo però può causare errori difficili da capire.
sin(0.5*pi) # seno di pi / 2
1.0
sin = 10 # Questo ridefinisce il nome `sin` associandolo ad un intero!
Dopo l'assegnazione sin = 10, il nome sin non punta più alla funzione trigonometrica ma a un intero.
Se provi a chiamare sin(0.5*pi), Python segnala che l'oggetto non è callable, cioè non è una funzione eseguibile.
Un modo per evitare questo tipo di errori è quello di scegliere nomi di variabili che non siano già usati da funzioni o keyword di Python. Se però ti accorgi di aver sovrascritto un nome importante, puoi sempre riavviare il kernel per resettare la memoria e ripristinare i nomi originali.
sin(0.5*pi)
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In[14], line 1 ----> 1 sin(0.5*pi) TypeError: 'int' object is not callable
Esercizio avanzato - Funzioni come variabili¶
Il seguente codice definisce una variabile stampa che contiene la funzione print (senza parentesi) e poi prova a eseguire stampa(0). Cosa ti aspetti che succeda? Prova a eseguirlo e verifica se le tue aspettative sono corrette.
# Esercizio avanzato: salvare una funzione in una variabile
# Rimuovi il carattere di commento `#` dall'inizio della riga qui sotto per rendere la riga eseguibile
#stampa = print
#stampa(0)
Suggerimento pratico: in Jupyter molti nomi noti di Python sono evidenziati con colori specifici. Se il nome di una variabile coincide con funzioni comuni (sum, len, list, ecc.), conviene cambiarlo per evitare conflitti.
Usare Markdown per il testo¶
Il tipo di cella può essere cambiato tra:
code(eseguibile, scorciatoiaEscpoiYo dal menu a tendina),raw(testo non formattato),markdown(testo formattato, scorciatoiaEscpoiMo dal menu a tendina).
Markdown è un linguaggio di formattazione (come lo è LaTeX) semplice ma molto utile per scrivere relazioni tecniche. Guida rapida: Markdown Cheat Sheet
Notate che cliccando su una cella due volte compare il testo non formattato ed editabile.
Elementi base utili¶
LaTeX¶
Per formule inline usa $...$, ad esempio $\sin^2(x)+\cos^2(x)=1$.
Per formule in blocco usa $$...$$, ad esempio:
$$\vec{F} = m\vec{a}$$
Immagini¶
Puoi inserire immagini con la sintassi Markdown: .
Suggerimento: per condividere un notebook, conserva sempre una struttura ordinata di cartelle (ad esempio notebook + sottocartella images) con all'interno le immagini usate. Ricordati di condividere anche le immagini insieme al notebook, altrimenti chi apre il file non vedrà le immagini.
Esempio di immagine non condivisa correttamente:

Immagine condivisa correttamente:

Leggere e salvare dati¶
Ci sono molti modi per lavorare con file di dati, ma nella pratica uno degli strumenti più utili è numpy.
numpy è una libreria fondamentale per il calcolo scientifico in Python che fornisce un modo per gestire array numerici in modo efficiente, ed implementa al suo interno molte operazioni matematiche già pronte all'uso. Per questo motivo è la base di gran parte dell'ecosistema scientifico Python e vale la pena imparare a usarla fin da subito.
Visto che vi servirà molto nei prossimi 5 anni, inizieremo ad utilizzarla già dalla pressime lezioni, ma per chi vuole approfondire subito, il sito ufficiale di numpy offre molte risorse utili, tra cui tutorial, documentazione e esempi pratici.
Per approfondire: NumPy Learn
import numpy as np
# Esempio: crea un piccolo array numerico
x = np.array([1, 2, 3, 4, 5])
x
array([1, 2, 3, 4, 5])
# Esempio: salva l'array su file e rileggilo
np.savetxt('esempio_dati.txt', x)
# Leggi i dati appena salvati sul file
x_letto = np.loadtxt('esempio_dati.txt')
x_letto
array([1., 2., 3., 4., 5.])