Torna al catalogo
Season 34 7 Episodi 26 min 2026

NumPy

v2.4 — Edizione 2026. Un corso audio che introduce NumPy, spiegando le sue alte prestazioni, gli array multidimensionali e il suo ruolo fondamentale nell'ecosistema Python. (v2.4, Edizione 2026)

Scienza dei Dati Python Core
NumPy
In Riproduzione
Click play to start
0:00
0:00
1
L'identità principale: ndarray
Questo episodio tratta l'oggetto ndarray, i tipi di dati omogenei e l'allocazione fissa della memoria. Imparerai perché le liste Python standard sono inefficienti per calcoli matematici su larga scala e come NumPy risolve questo problema passando al codice C compilato.
3m 45s
2
Evocare gli array: Creazione e forma
Questo episodio esplora come creare correttamente array multidimensionali utilizzando funzioni intrinseche. Imparerai a usare strumenti come zeros, arange e linspace per generare dataset all'istante.
3m 43s
3
Sotto il cofano: Memoria, stride e view
Questo episodio si immerge nell'architettura interna di NumPy, concentrandosi sul data buffer e sugli stride. Imparerai perché operazioni come lo slicing e la trasposizione sono virtualmente istantanee poiché restituiscono view di memoria, non copie.
3m 40s
4
Universal Functions: Matematica senza cicli
Questo episodio tratta le Universal Functions (ufuncs) e come vettorializzano le operazioni. Imparerai a eliminare completamente i cicli for di Python applicando calcoli matematici elemento per elemento e riduzioni basate sugli assi.
3m 49s
5
Broadcasting: La magia delle forme incompatibili
Questo episodio spiega le regole esatte del Broadcasting. Imparerai come NumPy allunga concettualmente array di forme incompatibili in modo che possano essere elaborati insieme senza sprecare memoria.
3m 58s
6
Filtraggio di precisione: Boolean Masking
Questo episodio si concentra sul boolean masking avanzato per filtrare dataset complessi. Imparerai come estrarre data point altamente specifici da array enormi utilizzando una semplice logica condizionale.
3m 34s
7
Il traduttore universale: Interoperabilità
Questo episodio rivela perché NumPy rimane la spina dorsale della data science in Python. Imparerai come DLPack e l'array interface consentono la condivisione della memoria zero-copy tra strumenti come Pandas e PyTorch.
3m 34s

Episodi

1

L'identità principale: ndarray

3m 45s

Questo episodio tratta l'oggetto ndarray, i tipi di dati omogenei e l'allocazione fissa della memoria. Imparerai perché le liste Python standard sono inefficienti per calcoli matematici su larga scala e come NumPy risolve questo problema passando al codice C compilato.

Download
Ciao, sono Alex di DEV STORIES DOT EU. NumPy, episodio 1 di 7. La list standard di Python è estremamente flessibile, ma nel momento in cui provi a fare operazioni matematiche su un milione di elementi, ti scontri con un muro di performance. Finisci per pagare una tassa enorme sui pointer solo per moltiplicare dei numeri tra loro. La soluzione a questo bottleneck è il motore principale del calcolo scientifico in Python: l'ndarray. Per capire perché esiste l'ndarray, devi guardare cosa fanno le list standard sotto il cofano. Una list di Python non memorizza numeri grezzi. Memorizza dei pointer. Ogni pointer indirizza il sistema verso una posizione sparsa in memoria dove risiede un object Python completo. Se scrivi un loop standard per moltiplicare due sequenze di un milione di numeri, l'interpreter Python fa una fatica enorme. Per ogni singolo elemento, recupera il pointer, individua l'object, controlla il suo data type per confermare che sia effettivamente un numero, esegue il calcolo matematico e memorizza il nuovo object. Fare questo un milione di volte introduce un overhead notevole. Questo ciclo continuo di pointer-chasing e type-checking è il motivo per cui i loop standard sono semplicemente troppo lenti per le grandi operazioni matematiche. L'ndarray, che sta per array N-dimensionale, rinuncia a questa flessibilità in cambio di velocità pura. La parte N-dimensionale significa che questo object può rappresentare una sequenza piatta di numeri, una griglia bidimensionale o una complessa matrice matematica multidimensionale. Indipendentemente da quante dimensioni definisci, sotto il cofano opera secondo due regole rigorose. Primo, richiede dei data type omogenei. Ogni singolo elemento in un ndarray deve essere esattamente dello stesso type, come ad esempio un float a 64 bit. Secondo, utilizza una dimensione di memoria fissa. Quando crei un ndarray, NumPy riserva un singolo blocco di memoria continuo. Non ci sono pointer. I numeri grezzi sono disposti in modo compatto uno accanto all'altro nella memoria di sistema. Ecco il punto chiave. Dato che NumPy conosce l'esatto data type e l'esatto memory layout, può bypassare completamente il lento interpreter Python. Quando moltiplichi due ndarray che contengono un milione di numeri, non scrivi un loop. Scrivi semplicemente array A moltiplicato per array B. Questo processo è chiamato vectorization. NumPy prende il tuo comando e affida il calcolo effettivo a del codice C precompilato. Il codice C macina quel blocco continuo di memoria a velocità hardware. Salta il type-checking e i pointer lookup per i singoli elementi, perché la memoria è perfettamente uniforme. Il trade-off per questo enorme aumento di velocità è la rigidità strutturale. Dato che la memoria è un blocco continuo, non puoi semplicemente fare l'append di un nuovo numero a un ndarray come fai con una list di Python. Se ti serve un array più grande, in genere NumPy deve allocare un blocco di memoria completamente nuovo e copiarci sopra i vecchi dati. Costruisci il contenitore della dimensione esatta che ti serve, e poi esegui le tue operazioni sull'intero blocco in una sola volta. La list standard di Python è una collezione di object isolati sparsi per la memoria. L'ndarray di NumPy è un blocco denso e uniforme di dati grezzi, progettato per essere elaborato istantaneamente da codice C ottimizzato. Se ti piacciono questi episodi e vuoi supportare lo show, puoi cercare DevStoriesEU su Patreon. Per questo episodio è tutto. Grazie per l'ascolto, e continua a sviluppare!
2

Evocare gli array: Creazione e forma

3m 43s

Questo episodio esplora come creare correttamente array multidimensionali utilizzando funzioni intrinseche. Imparerai a usare strumenti come zeros, arange e linspace per generare dataset all'istante.

Download
Ciao, sono Alex di DEV STORIES DOT EU. NumPy, episodio 2 di 7. Nella data science, raramente scrivi i dati a mano. Piuttosto, devi creare enormi griglie vuote e intervalli numerici dal nulla con un singolo comando. Parliamo delle funzioni native che ti permettono di creare array da zero e controllarne la struttura. Innanzitutto, una rapida correzione sulla creazione manuale. Quando converti una lista Python standard in un array usando la funzione array di base, un errore comune è passare più argomenti separati per creare più dimensioni. La funzione si aspetta una singola sequenza. Per creare un array bidimensionale, passi una lista che contiene altre liste, non due liste separate. Ogni array che crei porta con sé dei metadati strutturali. Due proprietà sono le più importanti in questo caso. La prima è ndim, che ti dice il numero di assi, o dimensioni, che ha l'array. Una sequenza piatta ha un ndim pari a uno, mentre una griglia piatta ha un ndim pari a due. La seconda proprietà è shape. Shape è una tupla di interi che indica la dimensione esatta dell'array lungo ogni dimensione. Se hai una matrice con due righe e tre colonne, la sua shape è due per tre. La lunghezza della tupla shape sarà sempre uguale al valore di ndim. Creare array da liste esistenti va bene per piccoli test, ma il vero lavoro richiede di generare array programmaticamente. Se ti serve un placeholder da riempire con dei dati in seguito, usi le funzioni zeros o ones. Ti basta passare una tupla shape a queste funzioni, e loro ti restituiscono un array con quell'esatta struttura, popolato interamente di zeri o uni. Di default, queste funzioni creano numeri floating-point, ma puoi sovrascrivere questo comportamento specificando un data type diverso. Quando ti serve una sequenza di numeri, NumPy fornisce due strumenti principali. Il primo è arange, che funziona in modo molto simile al range standard di Python. Gli dai un valore di partenza, un valore di fine e una dimensione di step. Genera un array di numeri distanziati da quello step. Anche se arange è ottimo per gli interi, usarlo con step floating-point può causare risultati imprevedibili a causa di come i computer gestiscono la precisione decimale. Il numero di elementi che ottieni indietro potrebbe variare leggermente a causa di microscopici errori di arrotondamento. Questo ci porta a linspace, che risolve il problema della precisione dei floating-point. Invece di definire la dimensione dello step, definisci il numero esatto di elementi che vuoi. Dai a linspace un valore di partenza, un valore di fine e il numero totale di punti. NumPy calcola la spaziatura esatta per te. Considera uno scenario in cui stai valutando una funzione matematica su un intervallo specifico. Vuoi calcolare la funzione su una griglia continua di coordinate tra zero e uno. Usando linspace, puoi generare esattamente cento coordinate equamente spaziate su quell'intervallo. Ottieni un array unidimensionale perfettamente distribuito, garantendo che siano inclusi sia il limite iniziale che quello finale. È qui che la cosa si fa interessante. La distinzione tra questi due generatori di sequenze detta il tuo workflow. Usa arange quando la dimensione esatta dello step è importante, ad esempio per contare gli interi a due a due, ma usa sempre linspace quando lavori con float e intervalli, in modo da poter garantire esattamente quanti data point ottieni e rispettare con precisione i tuoi limiti. Grazie per l'ascolto, ci sentiamo la prossima volta.
3

Sotto il cofano: Memoria, stride e view

3m 40s

Questo episodio si immerge nell'architettura interna di NumPy, concentrandosi sul data buffer e sugli stride. Imparerai perché operazioni come lo slicing e la trasposizione sono virtualmente istantanee poiché restituiscono view di memoria, non copie.

Download
Ciao, sono Alex di DEV STORIES DOT EU. NumPy, episodio 3 di 7. Hai una matrice di un miliardo di pixel e devi invertire le sue righe e colonne. Se lo fai in Python standard, la tua macchina si bloccherà mentre copia gigabyte di dati. In NumPy, questa operazione avviene istantaneamente. Riordinare quei pixel in realtà non sposta un singolo byte di memoria. Questo succede grazie a come NumPy gestisce memoria, stride e view dietro le quinte. Per capire perché NumPy è così veloce, devi guardare la struttura interna di un array. Un array NumPy non è un singolo oggetto monolitico. È rigorosamente suddiviso in due parti. La prima parte è il data buffer. È un blocco contiguo e piatto di memoria raw. È semplicemente una linea unidimensionale di byte che risiede nella RAM. Il raw buffer non sa assolutamente nulla di righe, colonne o dimensioni. La seconda parte sono i metadata. È un piccolo header, implementato internamente come una struttura C, che dice a NumPy come interpretare quella linea di byte raw. I metadata contengono un pointer all'inizio del data buffer, il data type, la shape dell'array e gli stride. Gli stride sono il meccanismo che trasforma una linea piatta di memoria in una griglia multidimensionale. Uno stride è semplicemente il numero di byte di cui il computer deve avanzare in memoria per trovare l'elemento successivo lungo un asse specifico. Supponi di avere un array bidimensionale di interi a 64 bit. Ogni intero occupa otto byte. Per spostarti di una colonna a destra, lo stride potrebbe essere di otto byte. Ma per scendere alla riga successiva, lo stride potrebbe essere di ottanta byte, perché deve saltare un'intera riga di dati nel raw buffer per trovare l'inizio di quella successiva. Molti sviluppatori presumono che quando fai uno slice di un array, il sistema allochi nuova memoria e copi i dati selezionati. Questo è sbagliato. Quando richiedi uno slice, NumPy lascia il raw data buffer completamente intatto. Invece, crea un nuovo header di metadata. Questo nuovo header punta esattamente allo stesso blocco di memoria, ma cambia il pointer iniziale e modifica gli stride per saltare gli elementi che hai escluso. Questa viene chiamata view. Ecco il punto chiave. Dato che i raw data e i metadata sono tenuti separati, le operazioni che cambiano la shape o l'ordine dell'array sono quasi completamente gratuite. Ripensa alla trasposizione di quell'enorme matrice da un miliardo di pixel. NumPy non prende i dati per riorganizzarli fisicamente. Scambia semplicemente i valori degli stride nel nuovo header di metadata. Il numero di byte che saltavi per trovare la riga successiva diventa il numero che salti per trovare la colonna successiva. Al tuo codice viene restituita una struttura di array completamente diversa, ma è solo una view che guarda alla stessa identica memoria fisica. Questa separazione è alla base dell'efficienza di memoria di NumPy. Puoi ritagliare un enorme dataset in decine di slice sovrapposti, passarli a diverse funzioni e consumare zero memoria extra per i dati stessi. Stai solo generando minuscoli header di metadata. Tuttavia, questo significa che condividi lo stato. Modificare un valore in uno slice altererà l'array originale, perché c'è un solo vero data buffer sotto a tutti quanti. La separazione dei byte raw dalle regole che li governano significa che le tue trasformazioni di dati più pesanti sono spesso solo dei leggeri scambi di metadata. Questo è tutto per questo episodio. Grazie per aver ascoltato, e continua a sviluppare!
4

Universal Functions: Matematica senza cicli

3m 49s

Questo episodio tratta le Universal Functions (ufuncs) e come vettorializzano le operazioni. Imparerai a eliminare completamente i cicli for di Python applicando calcoli matematici elemento per elemento e riduzioni basate sugli assi.

Download
Ciao, sono Alex di DEV STORIES DOT EU. NumPy, episodio 4 di 7. Se ti capita di scrivere un for-loop per moltiplicare i numeri in un array, fermati. Farlo significa che stai pagando l'overhead dell'interpreter Python su ogni singolo elemento, e il tuo codice gira cento volte più lentamente del necessario. La soluzione è usare le universal function per eseguire operazioni matematiche senza loop. Un errore comune è cercare di passare un intero array a una funzione del modulo math standard di Python. Se passi un milione di letture dei sensori a math punto sin, Python lancia un errore. Il modulo math standard capisce solo singoli valori scalar. Per processare un array, normalmente dovresti scrivere un loop. Ma Python è un linguaggio dinamico. All'interno di un loop, l'interpreter valuta il data type a ogni singola iterazione prima di calcolare il risultato. Quando processi dataset enormi, quelle minuscole pause di type-checking si sommano e diventano un bottleneck di performance significativo. Una universal function, o ufunc, risolve questo problema operando automaticamente sugli array elemento per elemento. Quando chiami una ufunc, NumPy delega l'esecuzione del loop al codice C compilato. Dato che gli array NumPy hanno un singolo data type uniforme, il codice C non ha bisogno di fermarsi a controllare i tipi. Itera su blocchi di memoria contigui e calcola il risultato alla massima velocità consentita dal tuo processore. Guardiamo uno scenario concreto. Hai un array che contiene migliaia di letture di sensori ambientali, e devi applicare una trasformazione matematica a tutte quante contemporaneamente. Invece di scrivere un loop, passi semplicemente l'intero array a una universal function come numpy punto exp o numpy punto sin. La ufunc prende il tuo array di input, esegue il loop veloce a livello C su ogni singolo elemento, e restituisce un array completamente nuovo popolato con le letture trasformate. Questa è la parte che conta. Le ufunc fanno molto di più di semplici trasformazioni elemento per elemento. Contengono metodi built-in per collassare i dati, bypassando completamente Python per le aggregazioni. Il più comune è il metodo reduce. Supponi di aver applicato la tua trasformazione matematica, e ora ti serve la somma totale dell'intero array. Chiami il metodo reduce direttamente sulla ufunc addition. Scrivi numpy punto add punto reduce, e gli passi il tuo array. Il metodo reduce applica l'operazione di addition sottostante ai primi due elementi. Prende quella somma, la aggiunge al terzo elemento, e continua questo schema finché l'intero array non viene collassato in un singolo valore scalar. Se i tuoi dati hanno dimensioni multiple, puoi controllare come avviene questo collasso. Se le letture dei tuoi sensori formano una griglia bidimensionale, dove le righe sono sensori diversi e le colonne sono singoli timestamp, ridurre l'intera griglia a un solo numero distrugge quella struttura. Fornendo un argomento axis, controlli la direzione dell'operazione. Se dici al metodo reduce di operare lungo l'axis zero, collassa le righe, lasciandoti con un array che contiene la somma di tutti i sensori a ogni singolo timestamp. Ogni volta che lasci che una universal function gestisca l'iterazione nativamente, stai scambiando i lenti loop Python con un'esecuzione C ottimizzata per l'hardware. Grazie per averci seguito. Alla prossima!
5

Broadcasting: La magia delle forme incompatibili

3m 58s

Questo episodio spiega le regole esatte del Broadcasting. Imparerai come NumPy allunga concettualmente array di forme incompatibili in modo che possano essere elaborati insieme senza sprecare memoria.

Download
Ciao, sono Alex di DEV STORIES DOT EU. NumPy, episodio 5 di 7. Cosa succede quando provi a moltiplicare una matrice tridimensionale di un milione di pixel per un singolo piccolo array di tre numeri? In molti linguaggi rigorosi, ottieni un errore di shape mismatch. In NumPy, semplicemente funziona. Questo comportamento si chiama broadcasting. Il broadcasting descrive come NumPy gestisce gli array con shape diverse durante le operazioni aritmetiche. Prende l'array più piccolo e, concettualmente, lo estende su quello più grande in modo che le loro shape si allineino perfettamente. Spesso chi ascolta crede erroneamente che questa estensione copi fisicamente i dati per creare un nuovo array corrispondente in memoria. Non è così. NumPy gestisce questo allineamento implicitamente a livello C. Itera sugli stessi elementi più volte con zero memory overhead, il che rende il broadcasting incredibilmente veloce ed efficiente. Per usarlo, devi capire come NumPy decide se due array sono compatibili. Non guarda il numero totale di elementi. Guarda le tuple delle shape. NumPy allinea le shape dei due array e le confronta partendo dalle trailing dimensions, ovvero quelle più a destra, e procede verso sinistra. Due dimensioni sono compatibili se soddisfano una di due condizioni rigorose. Devono essere esattamente uguali, oppure una di esse deve essere il numero uno. Se nessuna delle due condizioni viene soddisfatta in un qualsiasi punto del confronto, NumPy lancia un ValueError e l'operazione fallisce. Applichiamo questo concetto a uno scenario concreto. Stai lavorando con un'immagine RGB. La carichi in un array NumPy con una shape di 256 per 256 per 3. Il 3 rappresenta i canali di colore rosso, verde e blu alla fine della shape. Ora, devi correggere il colore di questa immagine scalando ciascun canale in modo diverso. Definisci un array unidimensionale contenente tre pesi di correzione del colore. La shape di questo array è semplicemente 3. Quando moltiplichi l'enorme array dell'immagine per il piccolo array dei pesi, NumPy applica la regola da destra a sinistra. Posiziona la shape dell'immagine, 256 per 256 per 3, sopra la shape dei pesi, che è solo 3. Partendo dall'estrema destra, vengono confrontate le trailing dimensions. Entrambe sono 3. Poiché sono uguali, sono compatibili. Quindi, NumPy si sposta a sinistra. L'array dell'immagine ha una dimensione di 256, ma l'array dei pesi ha esaurito completamente le dimensioni. È qui che entra in gioco la seconda parte della regola. Quando un array ha meno dimensioni dell'altro, NumPy aggiunge implicitamente degli uno all'inizio della sua shape finché non corrispondono in lunghezza. La shape dell'array dei pesi viene trattata come 1 per 1 per 3. Ora il confronto continua. L'immagine ha una dimensione di 256 e l'array dei pesi ora ha una dimensione di 1. Poiché uno dei due è un 1, sono compatibili. L'array dei pesi viene concettualmente esteso lungo le 256 righe. Questo succede di nuovo per la dimensione successiva. Le shape si allineano e NumPy applica i tuoi tre pesi di colore a tutti i sessantacinquemila pixel in modo impeccabile. Questa è la parte che conta. La regola funziona solo da destra a sinistra. Se hai un array bidimensionale con una shape di 5 per 4, e provi a sommare un array di shape 5, potresti pensare che si estenda lungo le colonne. Non lo farà. Partendo da destra, NumPy confronta 4 e 5. Non sono uguali, e nessuno dei due è un uno. L'operazione fallisce all'istante. Per farla funzionare, dovresti prima fare un reshape del secondo array a 5 per 1. Il broadcasting ti permette di scrivere codice pulito e senza loop, che viene eseguito a velocità di compilazione. La regola d'oro è sempre le trailing dimensions prima di tutto: devono corrispondere esattamente, oppure una di esse deve essere un uno. Grazie per averci seguito. Alla prossima!
6

Filtraggio di precisione: Boolean Masking

3m 34s

Questo episodio si concentra sul boolean masking avanzato per filtrare dataset complessi. Imparerai come estrarre data point altamente specifici da array enormi utilizzando una semplice logica condizionale.

Download
Ciao, sono Alex di DEV STORIES DOT EU. NumPy, episodio 6 di 7. Estrarre ogni numero negativo da un array di un miliardo di elementi non è un problema di ricerca. Non dovrebbe richiedere un loop, e certamente non dovrebbe rallentare la tua applicazione. È qui che usiamo il filtraggio di precisione: il boolean masking. Il basic slicing estrae blocchi di dati ordinati e prevedibili. Ma i dati del mondo reale sono disordinati. Raramente vuoi solo i primi dieci elementi. Vuoi elementi specifici in base a una condizione logica, e questi elementi potrebbero essere sparsi casualmente nel tuo dataset. In NumPy, estrarre dati in questo modo si chiama advanced indexing, e il boolean masking è una delle sue forme più potenti. Prendi un enorme array di letture di temperatura. Devi isolare solo i valori che scendono sotto lo zero. Invece di scrivere un loop per controllare ogni singola lettura, usi una mask. Una mask è un array di valori boolean, ovvero True o False. La cosa fondamentale è che questo array boolean ha esattamente la stessa shape del tuo array di dati originale. La crei applicando una condizione di minore di zero direttamente all'array. NumPy valuta all'istante ogni singolo elemento. Se una temperatura è sotto lo zero, la mask registra un True in quell'esatta posizione. Se la temperatura è pari o superiore a zero, registra un False. Una volta ottenuta questa mask, la applichi di nuovo all'array originale passandola esattamente dove normalmente metteresti un index. NumPy legge la mask, seleziona ogni elemento in cui la mask è True e scarta il resto. L'operazione produce un array unidimensionale completamente nuovo, che contiene solo le tue temperature sotto zero. Avviene tutto in un unico passaggio, gestito a basso livello da codice C altamente ottimizzato. Fai attenzione a questa prossima distinzione, perché confonde un sacco di sviluppatori. Devi sapere esattamente cosa ti restituisce NumPy quando filtri i dati. Il basic slicing restituisce una view. Se fai lo slicing dei primi dieci elementi di un array e li modifichi, l'array originale cambia. Il boolean masking si comporta in modo completamente diverso. Poiché il boolean masking è una forma di advanced indexing, restituisce sempre una copy dei dati, mai una view. Il motivo è l'architettura della memoria. Quando fai slicing, NumPy si limita a modificare i pointers a un blocco di memoria continuo ed esistente. Ma quando applichi una boolean mask, gli elementi che selezioni sono completamente arbitrari. Non si trovano più ordinatamente uno accanto all'altro in memoria. NumPy deve raccoglierli e allocare nuovo spazio per memorizzare il risultato. Questo significa che se modifichi il tuo nuovo array filtrato di temperature sotto zero, il tuo dataset originale rimane completamente intatto. Puoi anche fare chaining di queste condizioni. Se hai bisogno di temperature che siano sotto lo zero ma strettamente sopra i meno dieci gradi, combini le due condizioni logiche. NumPy valuta la logica combinata elemento per elemento e costruisce un'unica mask precisa. Quando applichi una boolean mask, stai scambiando l'efficienza di memoria di una view per una precisione di filtraggio assoluta, ottenendo una copy intatta e indipendente esattamente dei dati che hai richiesto. Questo è tutto per questo episodio. Grazie per l'ascolto, e continua a sviluppare!
7

Il traduttore universale: Interoperabilità

3m 34s

Questo episodio rivela perché NumPy rimane la spina dorsale della data science in Python. Imparerai come DLPack e l'array interface consentono la condivisione della memoria zero-copy tra strumenti come Pandas e PyTorch.

Download
Ciao, sono Alex di DEV STORIES DOT EU. NumPy, episodio 7 di 7. Con i moderni framework GPU che gestiscono il grosso del lavoro nel machine learning, potresti pensare che NumPy stia diventando obsoleto. Potresti persino supporre che convertire un CPU tensor di PyTorch in un array NumPy richieda un lento memory copy, rallentando la tua pipeline. Nessuna delle due cose è vera. La realtà è che NumPy fa da Traduttore Universale: Interoperabilità, tenendo insieme l'intero ecosistema dati di Python. Pensa a una pipeline di machine learning standard. Usi Pandas per caricare e pulire un enorme dataset tabellare. Estrai questi valori in NumPy per applicare un filtro matematico specializzato. Infine, passi quei dati filtrati a PyTorch per addestrare una rete neurale. Se ciascuna di queste librerie isolasse i propri dati, passare da uno step all'altro significherebbe duplicare l'intero dataset in memoria più e più volte. Esauriresti la tua RAM e sprecheresti tempo di elaborazione solo per spostare byte. Invece, grazie alla magia dell'interoperabilità, i dati non si spostano mai veramente. Pandas, NumPy e PyTorch condividono semplicemente lo stesso identico memory pointer sottostante. Quando PyTorch legge i dati, sta guardando gli stessi identici indirizzi di memoria fisica che Pandas aveva allocato originariamente. Questa condivisione zero copy è resa possibile da protocolli di memoria standard. Quello fondamentale è l'array interface. Se un oggetto Python espone questa interfaccia, in sostanza consegna un piccolo dizionario di metadati. Questi metadati dicono a NumPy esattamente dove iniziano i raw data in memoria, che shape hanno e quale data type contengono. Quando chiami una funzione NumPy su un oggetto compatibile, NumPy legge quelle istruzioni e avvolge la propria struttura array attorno al blocco di memoria esistente. Non crea un nuovo array; crea semplicemente una nuova view dei vecchi dati. Ecco il punto chiave. L'array interface originale era stata progettata principalmente per la memoria di sistema standard. Man mano che la data science si è spostata sugli acceleratori hardware, l'ecosistema ha avuto bisogno di un modo per condividere i dati residenti su GPU o chip custom senza doverne fare il routing di nuovo attraverso la CPU. Questo ha portato all'adozione di DLPack. DLPack è uno standard moderno e aperto per condividere array multidimensionali tra diversi framework. Definisce una struttura stabile che qualsiasi libreria può produrre e consumare. Se hai un tensor in un framework come PyTorch o JAX, puoi esportarlo usando il protocollo DLPack. NumPy può quindi importarlo senza problemi usando la sua funzione dedicata from dlpack. Anche se NumPy opera principalmente sulla CPU, il suo supporto per DLPack significa che può fare da routing hub centrale. Puoi passare un oggetto DLPack da un framework di deep learning a NumPy, o da NumPy di nuovo a un framework, il tutto senza costose duplicazioni di dati. NumPy ha smesso da molto tempo di essere solo una libreria matematica. È il memory standard invisibile che impedisce all'ecosistema dati di Python di frammentarsi in isole separate e incompatibili. Ti incoraggio a esplorare la documentazione ufficiale, a provare queste conversioni zero copy hands-on nel tuo terminale, o a visitare devstories dot eu per suggerire argomenti per le nostre serie future. Questo è tutto per questo episodio. Grazie per l'ascolto, e continua a sviluppare!