# Pandas 3.0 nel 2026: Nuove API, Breaking Changes e Domande di Colloquio > Pandas 3.0 introduce Copy-on-Write come comportamento predefinito, un dtype stringa basato su PyArrow e il nuovo expression builder pd.col(). Questo articolo approfondisce le modifiche principali, i pattern di migrazione e le domande di colloquio per data engineer. - Published: 2026-05-05 - Updated: 2026-05-05 - Author: SharpSkill - Tags: pandas, python, data-analytics, interview, pandas-3 - Reading time: 10 min --- Pandas 3.0, rilasciato il 21 gennaio 2026, introduce le modifiche architetturali più significative dall'era 1.x. Copy-on-Write diventa il comportamento predefinito, le colonne stringa passano a un dtype supportato da PyArrow, e il nuovo expression builder `pd.col()` offre un'alternativa più pulita alle funzioni lambda. Queste modifiche impattano ogni codebase esistente e vengono sempre più testate nei colloqui di data engineering. > **Punto Chiave** > > Pandas 3.0 richiede Python 3.11+, applica la semantica Copy-on-Write per impostazione predefinita e inferisce le colonne stringa come dtype `str` supportato da PyArrow. L'assegnazione concatenata ora genera un errore invece di un avviso. ## Copy-on-Write: La Fine del SettingWithCopyWarning Copy-on-Write (CoW) cambia fondamentalmente il modo in cui pandas gestisce la condivisione della memoria tra DataFrame. Ogni operazione di indicizzazione ora restituisce qualcosa che si comporta come una copia, ma pandas internamente condivide la memoria fino a quando non si verifica effettivamente una mutazione. L'impatto pratico: `SettingWithCopyWarning` non esiste più. Pattern di assegnazione concatenata come `df[df['A'] > 0]['B'] = 1` ora generano un `ChainedAssignmentError` perché il risultato intermedio dell'indicizzazione è una copia. ```python # migration_cow.py import pandas as pd df = pd.DataFrame({"price": [100, 200, 300], "category": ["A", "B", "A"]}) # Pattern Pandas 2.x (ora genera ChainedAssignmentError) # df[df["category"] == "A"]["price"] = 150 # NON FUNZIONA in 3.0 # Pattern corretto Pandas 3.0: usare .loc[] df.loc[df["category"] == "A", "price"] = 150 # CoW condivisione memoria in azione df2 = df[["price"]] # condivide memoria con df df2["price"] = df2["price"] * 2 # copia attivata solo qui # df rimane invariato - nessun effetto collaterale ``` L'argomento keyword `copy` non ha più alcun effetto in tutti i metodi e può essere rimosso in sicurezza dal codice esistente. I metodi che supportano `inplace=True` (`replace()`, `fillna()`, `ffill()`, `bfill()`, `clip()`) ora restituiscono `self` invece di `None`, abilitando il method chaining anche con operazioni in-place. ## Backend PyArrow per le Stringhe: Operazioni 5-10x Più Veloci Pandas 3.0 inferisce le colonne stringa come dtype dedicato `str` supportato da PyArrow, sostituendo il legacy dtype `object`. Se PyArrow non è installato, il fallback utilizza array di oggetti NumPy. I guadagni in termini di prestazioni sono sostanziali: `.str.contains()`, `.str.lower()` e altri metodi stringa funzionano 5-10x più velocemente. Il consumo di memoria per colonne ricche di testo scende fino al 50%. Il formato colonnare Arrow consente anche lo scambio di dati zero-copy con Polars, DuckDB e altri strumenti nativi Arrow. ```python # string_dtype_comparison.py import pandas as pd import numpy as np # Pandas 3.0: le colonne stringa sono automaticamente str[pyarrow] df = pd.DataFrame({"name": ["Alice", "Bob", "Charlie", None]}) print(df.dtypes) # name string[pyarrow] # dtype: object # I valori mancanti usano NaN (non pd.NA) print(df["name"].isna()) # True per l'elemento None # Interoperabilità diretta con DuckDB (zero-copy) import duckdb result = duckdb.sql("SELECT name FROM df WHERE name LIKE '%li%'").df() ``` Un vincolo importante: gli array PyArrow sono immutabili. La conversione di una colonna supportata da PyArrow in un array NumPy scrivibile richiede una copia esplicita tramite `.to_numpy(copy=True)`. > **Avviso di Migrazione** > > Il codice che controlla `df['col'].dtype == object` per il rilevamento delle stringhe non funzionerà più. Sostituire con `pd.api.types.is_string_dtype(df['col'])` o verificare `pd.StringDtype()`. ## L'Expression Builder pd.col() Pandas 3.0 introduce `pd.col()` come modo dichiarativo per referenziare le colonne del DataFrame e costruire espressioni. La sintassi si ispira a PySpark e Polars, risolvendo problemi noti con lo scoping delle lambda e la loro opacità. ```python # col_expressions.py import pandas as pd df = pd.DataFrame({ "revenue": [1000, 2500, 800, 3200], "cost": [400, 1200, 600, 1500], "region": ["US", "EU", "US", "APAC"] }) # Prima: basato su lambda (opaco, problemi di scoping nei loop) df = df.assign(profit=lambda x: x["revenue"] - x["cost"]) # Dopo: pd.col() (dichiarativo, introspezionabile) df = df.assign( profit=pd.col("revenue") - pd.col("cost"), margin=((pd.col("revenue") - pd.col("cost")) / pd.col("revenue") * 100) ) # Filtraggio con pd.col() high_margin = df.loc[pd.col("margin") > 50] ``` Il vantaggio chiave rispetto alle lambda emerge nei loop, dove le closure catturano le variabili per riferimento e producono risultati errati: ```python # loop_scoping_fix.py import pandas as pd df = pd.DataFrame({"base": [10, 20, 30]}) # Bug lambda: tutte le colonne usano factor=30 (ultimo valore del loop) # cols = {} # for factor in [2, 5, 10]: # cols[f"x{factor}"] = lambda x: x["base"] * factor # BUG # Fix pd.col(): ogni espressione cattura il valore corretto cols = {} for factor in [2, 5, 10]: cols[f"x{factor}"] = pd.col("base") * factor # Corretto df = df.assign(**cols) ``` A partire da pandas 3.0.2, `pd.col()` funziona anche in `Series.case_when()`. Le aggregazioni groupby non sono ancora supportate. ## Breaking Changes: Checklist Completa di Migrazione La tabella seguente riassume le breaking changes più probabili durante la migrazione da pandas 2.x: | Modifica | Comportamento Pandas 2.x | Comportamento Pandas 3.0 | Soluzione | |----------|--------------------------|--------------------------|----------| | Assegnazione concatenata | `SettingWithCopyWarning` | `ChainedAssignmentError` | Usare `.loc[]` | | Dtype stringa | `object` | `string[pyarrow]` | Aggiornare i controlli dtype | | Keyword `copy=` | Crea una copia | Nessun effetto (deprecato) | Rimuovere l'argomento | | `groupby(observed=)` | Default `False` | Default `True` | Impostare esplicitamente | | `Index.sort_values()` | Argomenti posizionali | Solo argomenti keyword | Nominare tutti gli argomenti | | `offsets.Day` | Span fisso 24h | Giorno di calendario (DST-aware) | Rivedere logica timezone | | `Categorical.map(na_action=)` | Default `None` | Default modificato | Impostare esplicitamente | | `str.contains(na=)` | Non-bool permesso | Solo bool o `None` | Pulire il parametro na | Il percorso di upgrade raccomandato: prima aggiornare a pandas 2.3, risolvere tutti gli avvisi di deprecation, poi passare a 3.0. ## Nuova Policy di Deprecation: Pandas4Warning e Pandas5Warning Pandas 3.0 introduce un ciclo di deprecation strutturato a 3 fasi. Le funzionalità prima emettono un `DeprecationWarning` standard, poi passano a un `FutureWarning` nell'ultima versione minor prima del prossimo major, e infine vengono rimosse nel major release. Due nuove classi di warning facilitano il filtraggio degli avvisi per versione target: ```python # filter_warnings.py import warnings import pandas as pd # Intercettare solo le modifiche in arrivo in pandas 4.0 warnings.filterwarnings("error", category=pd.errors.Pandas4Warning) # Intercettare le modifiche in arrivo in pandas 5.0 warnings.filterwarnings("default", category=pd.errors.Pandas5Warning) ``` Questa policy garantisce ai maintainer delle librerie almeno due cicli di minor release per adattarsi prima che le breaking changes diventino effettive. > **Versione Python** > > Pandas 3.0 richiede Python 3.11 o superiore. I progetti ancora su Python 3.9 o 3.10 devono aggiornare prima della migrazione. ## Domande di Colloquio: Pandas 3.0 in Profondità Queste domande compaiono nei colloqui di data engineering e analytics nel 2026, testando sia la comprensione teorica che l'esperienza pratica di migrazione. **D1: Spiegare Copy-on-Write in pandas 3.0. Perché è stato introdotto?** CoW garantisce che ogni DataFrame o Series restituito da un'operazione di indicizzazione si comporti come una copia indipendente. Internamente, pandas condivide la memoria tra originale e risultato fino a quando uno dei due viene mutato, momento in cui avviene una copia fisica. Questo elimina l'ambiguità tra viste e copie che causava `SettingWithCopyWarning`, previene la corruzione accidentale dei dati attraverso effetti collaterali e riduce l'utilizzo della memoria per carichi di lavoro a prevalenza di lettura. **D2: Cosa succede a `df[condition]['col'] = value` in pandas 3.0?** Genera un `ChainedAssignmentError`. L'intermedio `df[condition]` è ora sempre una copia (a causa di CoW), quindi l'assegnazione a una colonna su quella copia non ha effetto sul DataFrame originale. Il pattern corretto è `df.loc[condition, 'col'] = value`. **D3: Come influisce il nuovo dtype stringa sull'interoperabilità con altri strumenti?** Il dtype stringa supportato da PyArrow archivia i dati nel formato colonnare di Apache Arrow. Questo consente il trasferimento dati zero-copy verso altri strumenti nativi Arrow (Polars, DuckDB, Spark via PyArrow) senza overhead di serializzazione. Riduce anche l'impronta di memoria rispetto agli array di oggetti Python, poiché Arrow utilizza buffer binari compatti invece di singoli oggetti stringa Python. **D4: Quale problema risolve `pd.col()` che le lambda non possono?** `pd.col()` cattura i riferimenti alle colonne e i valori al momento della creazione dell'espressione, non al momento dell'esecuzione. Le lambda in Python catturano le variabili per riferimento, causando bug nei loop dove tutte le lambda finiscono per referenziare l'ultima variabile del loop. Inoltre, le espressioni `pd.col()` sono introspezionabili (pandas può ottimizzarle), mentre le lambda sono callable opachi. **D5: Come si migrerebbe una codebase da pandas 2.x a 3.0?** Passo 1: Aggiornare a pandas 2.3 e correggere tutti gli avvisi di deprecation. Passo 2: Abilitare l'opt-in CoW tramite `pd.options.mode.copy_on_write = True` (disponibile dalla 2.0) e correggere i pattern di assegnazione concatenata. Passo 3: Installare PyArrow e verificare che l'inferenza del dtype stringa non rompa la logica a valle (specialmente i controlli `dtype == object`). Passo 4: Aggiornare alla 3.0 ed eseguire l'intera suite di test. Passo 5: Rimuovere gli argomenti `copy=` inutilizzati e aggiornare le chiamate `groupby(observed=)`. ## Benchmark di Performance: Prima e Dopo L'effetto combinato di CoW e stringhe PyArrow offre miglioramenti misurabili su carichi di lavoro reali: ```python # benchmark_example.py import pandas as pd import numpy as np # Generare un DataFrame con 1M righe di dati misti rng = np.random.default_rng(42) df = pd.DataFrame({ "user_id": rng.integers(0, 100_000, size=1_000_000), "event": rng.choice(["click", "view", "purchase", "scroll"], size=1_000_000), "value": rng.exponential(50, size=1_000_000) }) # Filtraggio stringhe: ~6x più veloce con backend PyArrow clicks = df.loc[pd.col("event").str.contains("click")] # Memoria: colonna stringa usa ~50% meno RAM print(df["event"].memory_usage(deep=True)) # ~8MB vs ~16MB con dtype object # Subsetting: CoW evita la copia fino alla mutazione subset = df[["user_id", "value"]] # zero-copy (memoria condivisa) subset["value"] = subset["value"].clip(upper=500) # copia attivata solo qui ``` Nelle pipeline ETL di produzione che elaborano CSV ricchi di testo, il solo backend stringa PyArrow riduce il consumo di memoria di picco del 30-40% e taglia il tempo di esecuzione totale del 20-30% sulle trasformazioni intensive di stringhe. ## Migrazione Pratica: Correzioni di Pattern Reali Una tipica codebase pandas 2.x necessita di questi refactoring specifici: ```python # migration_patterns.py import pandas as pd # Pattern 1: Sostituire l'assegnazione concatenata # Prima (pandas 2.x) # df[df["status"] == "active"]["score"] = 100 # Dopo (pandas 3.0) df.loc[df["status"] == "active", "score"] = 100 # Pattern 2: Rimuovere gli argomenti copy= # Prima # subset = df[["a", "b"]].copy() # non necessario con CoW # Dopo subset = df[["a", "b"]] # CoW gestisce l'isolamento automaticamente # Pattern 3: Aggiornare i controlli dtype per le stringhe # Prima # if df["name"].dtype == object: # Dopo if pd.api.types.is_string_dtype(df["name"]): pass # Pattern 4: observed= esplicito in groupby # Prima (si basava sul default observed=False) # df.groupby("category")["value"].sum() # Dopo (esplicito per chiarezza) df.groupby("category", observed=True)["value"].sum() # Pattern 5: Solo keyword per Index.sort_values() # Prima # idx.sort_values(True, "first") # Dopo idx.sort_values(ascending=True, na_position="first") ``` Per approfondire le [competenze fondamentali di pandas e Python per data analytics](/technologies/data-analytics/interview-questions/python-pandas-basics), i moduli di domande di colloquio coprono questi pattern in dettaglio. Il [modulo sulle funzioni finestra SQL](/technologies/data-analytics/interview-questions/sql-window-functions) complementa la conoscenza di pandas per ruoli analytics ibridi SQL/Python. ## Conclusione - Copy-on-Write elimina completamente `SettingWithCopyWarning` e previene la mutazione accidentale dei dati attraverso riferimenti condivisi - Il backend stringa PyArrow offre operazioni sulle stringhe 5-10x più veloci e una riduzione del 50% della memoria per le colonne di testo - `pd.col()` sostituisce i pattern lambda soggetti a errori con espressioni dichiarative e introspezionabili - L'assegnazione concatenata (`df[cond]['col'] = val`) è ora un errore duro che richiede la migrazione a `.loc[]` - La policy di deprecation strutturata (`Pandas4Warning`, `Pandas5Warning`) fornisce timeline di upgrade chiare - Percorso di upgrade: prima pandas 2.3 (correggere gli avvisi), poi 3.0 (con PyArrow installato e Python 3.11+) - La preparazione ai colloqui dovrebbe concentrarsi sulla meccanica CoW, l'interoperabilità PyArrow e i pattern pratici di migrazione --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/it/blog/data-analytics/pandas-3-new-apis-breaking-changes-interview