Warum pandas 3.0 das wichtigste Python-Update 2026 ist
Am 21. Januar 2026 hat das pandas-Team die Version 3.0.0 veröffentlicht — das erste Major-Release seit Jahren. Und ganz ehrlich: Es ist kein sanftes Update. Copy-on-Write wird zum Standard, String-Spalten bekommen einen eigenen Datentyp, und mit pd.col() gibt es eine komplett neue Syntax für Spaltenausdrücke. Kurz gesagt: Das betrifft praktisch jeden, der regelmäßig mit pandas arbeitet.
Aber keine Panik.
In diesem Leitfaden gehen wir Schritt für Schritt durch alle wichtigen Änderungen, zeigen die häufigsten Stolperfallen beim Upgrade und liefern konkreten Code, den Sie direkt in Ihre Projekte übernehmen können. Also, legen wir los.
Voraussetzungen: Was Sie vor dem Upgrade wissen müssen
Bevor Sie jetzt wild pip install --upgrade pandas in die Konsole hauen, gibt es ein paar Dinge zu beachten:
- Python 3.11 oder höher ist Pflicht — pandas 3.0 unterstützt ältere Python-Versionen schlicht nicht mehr.
- PyArrow wird dringend empfohlen — der neue String-Datentyp nutzt PyArrow als Backend für deutlich bessere Performance. Ohne PyArrow fällt pandas auf den langsameren NumPy-object-Dtype zurück (und das will man wirklich nicht).
- Zuerst auf pandas 2.3 upgraden — das offizielle Team empfiehlt, zunächst auf Version 2.3 zu gehen. Dort bekommen Sie Deprecation-Warnungen, die auf nötige Code-Änderungen hinweisen. Vertrauen Sie mir: Dieser Zwischenschritt spart eine Menge Debugging-Frust.
Der empfohlene Upgrade-Pfad
# Schritt 1: Auf pandas 2.3 upgraden
pip install pandas==2.3.*
# Schritt 2: Code testen und alle Warnungen beheben
python -W error::DeprecationWarning mein_skript.py
# Schritt 3: Optional — neue Features vorab aktivieren
import pandas as pd
pd.options.future.infer_string = True
pd.options.mode.copy_on_write = True
# Schritt 4: Auf pandas 3.0 upgraden
pip install pandas==3.0.*
# Schritt 5: PyArrow installieren (empfohlen)
pip install pyarrow
Copy-on-Write: Die größte Verhaltensänderung
Copy-on-Write (CoW) ist die Änderung, die am meisten bestehenden Code betrifft. In früheren pandas-Versionen war das Verhalten bei Indexierungsoperationen oft — na ja — unvorhersehbar. Manchmal bekam man eine Kopie, manchmal eine View auf die Originaldaten. Das führte zu subtilen Bugs und dem berüchtigten SettingWithCopyWarning, den wahrscheinlich jeder pandas-Nutzer schon mal gesehen hat.
Ab pandas 3.0 gilt eine klare Regel: Jedes Ergebnis einer Indexierungsoperation oder Methode verhält sich immer wie eine Kopie. Das Original wird dadurch nie verändert. Intern nutzt pandas zwar weiterhin Views (aus Performance-Gründen), kopiert aber automatisch, sobald eine Änderung vorgenommen wird — daher der Name „Copy-on-Write".
Chained Assignment funktioniert nicht mehr
Das ist die Änderung, über die am meisten gestolpert wird. Chained Assignment — also das Modifizieren eines DataFrames über mehrere Indexierungsschritte hinweg — hat in pandas 3.0 schlicht keine Wirkung mehr:
import pandas as pd
df = pd.DataFrame({
"name": ["Anna", "Boris", "Clara"],
"gehalt": [65000, 55000, 72000],
"abteilung": ["IT", "Marketing", "IT"]
})
# FALSCH — funktioniert in pandas 3.0 nicht mehr!
# Die Zuweisung ändert nur eine temporäre Kopie, nicht df.
df["gehalt"][df["abteilung"] == "IT"] = 70000
# RICHTIG — direkte Modifikation mit .loc
df.loc[df["abteilung"] == "IT", "gehalt"] = 70000
print(df)
# Ausgabe:
# name gehalt abteilung
# 0 Anna 70000 IT
# 1 Boris 55000 Marketing
# 2 Clara 70000 IT
Falls Sie sich fragen, warum das überhaupt so funktionierte: In früheren Versionen hing es im Grunde vom Zufall ab, ob die Änderung auf dem Original oder einer Kopie landete. Jetzt ist das Verhalten wenigstens eindeutig.
Defensives .copy() ist nicht mehr nötig
Viele Entwickler (mich eingeschlossen) haben jahrelang vorsorglich .copy() aufgerufen, um den SettingWithCopyWarning loszuwerden. Da Copy-on-Write jetzt Standard ist, können Sie diese Aufrufe getrost entfernen:
# Vorher (pandas < 3.0) — defensives .copy()
subset = df[df["gehalt"] > 60000].copy()
subset["bonus"] = subset["gehalt"] * 0.1
# Nachher (pandas 3.0) — .copy() nicht mehr nötig
subset = df[df["gehalt"] > 60000]
subset["bonus"] = subset["gehalt"] * 0.1
# subset ist automatisch unabhängig von df
Performance-Vorteile durch CoW
Copy-on-Write verbessert nicht nur die Vorhersagbarkeit, sondern auch die Performance. Da pandas intern Views nutzt und erst beim Schreiben tatsächlich kopiert, werden unnötige Kopieroperationen vermieden. In der Praxis heißt das:
- Weniger Speicherverbrauch bei Subset-Operationen
- Schnellere Ausführung bei reinen Leseoperationen
- Konsistentes Verhalten — keine bösen Überraschungen mehr
Neuer String-Datentyp: Von object zu str
Das hier ist eine Änderung, auf die viele lange gewartet haben. Bisher hat pandas String-Spalten als NumPy object-Datentyp gespeichert — ein generischer Typ, der im Prinzip alles aufnehmen kann. Das war weder performant noch typsicher. Ab pandas 3.0 gibt es endlich einen dedizierten str-Datentyp, der standardmäßig für String-Daten verwendet wird.
Was sich ändert
import pandas as pd
# pandas < 3.0
ser = pd.Series(["Berlin", "München", "Hamburg"])
print(ser.dtype)
# Ausgabe: object
# pandas 3.0
ser = pd.Series(["Berlin", "München", "Hamburg"])
print(ser.dtype)
# Ausgabe: str
Intern nutzt der neue str-Dtype PyArrow als Backend (sofern installiert). Das bringt spürbare Performance-Verbesserungen — laut den Entwicklern bis zu 5–10x schnellere Verarbeitung bei textlastigen Workloads. Das klingt vielleicht übertrieben, aber bei großen DataFrames mit vielen Textspalten macht sich der Unterschied wirklich bemerkbar.
Häufige Fehler beim String-Dtype-Wechsel
Der neue String-Dtype kann bestehenden Code brechen, wenn dieser auf den object-Dtype prüft. Das ist ein Fehler, den man leicht übersieht:
import pandas as pd
df = pd.DataFrame({"stadt": ["Berlin", "München", "Hamburg"]})
# FALSCH — gibt in pandas 3.0 False zurück!
if df["stadt"].dtype == "object":
print("String-Spalte gefunden")
# RICHTIG — funktioniert mit allen pandas-Versionen
if pd.api.types.is_string_dtype(df["stadt"]):
print("String-Spalte gefunden")
NumPy-Kompatibilität beachten
Da der neue str-Dtype ein pandas Extension-Dtype ist (und kein NumPy np.dtype), können Sie ihn nicht direkt an NumPy-Funktionen übergeben:
import numpy as np
import pandas as pd
ser = pd.Series(["a", "b", "c"])
# FALSCH — funktioniert nicht mit dem neuen str-Dtype
# np.issubdtype(ser.dtype, np.object_)
# RICHTIG — pandas-eigene Typ-Prüfung verwenden
pd.api.types.is_string_dtype(ser) # True
PyArrow und Unicode
Ein kleiner Stolperstein: Wenn PyArrow als Backend aktiv ist, kann der String-Dtype nur gültige Unicode-Daten speichern. Ungültige Surrogates führen zu einem Fehler:
# Wirft einen UnicodeEncodeError mit PyArrow-Backend
# ser = pd.Series(["\ud83d"])
# Lösung: Explizit object-Dtype angeben
ser = pd.Series(["\ud83d"], dtype="object")
In den meisten Fällen werden Sie dieses Problem nie sehen. Aber wenn Sie mit Daten aus externen Quellen arbeiten, die nicht immer sauberes Unicode liefern, sollten Sie das im Hinterkopf behalten.
pd.col() — Die neue Spaltenausdrucks-Syntax
Inspiriert von Polars und PySpark führt pandas 3.0 die Funktion pd.col() ein. Damit können Sie auf DataFrame-Spalten verweisen und Ausdrücke aufbauen — ganz ohne Lambda-Funktionen. Und ehrlich gesagt: Das war längst überfällig.
Warum pd.col() besser ist als Lambda
Lambda-Funktionen haben in pandas mehrere Probleme: Sie sind schwer zu lesen, nicht introspektierbar und anfällig für Scoping-Bugs. Hier ein klassisches Beispiel, das schon vielen Kopfschmerzen bereitet hat:
import pandas as pd
df = pd.DataFrame({"x": [1, 2, 3]})
# Scoping-Bug mit Lambda
results = {}
for factor in [10, 20, 30]:
results[f"x_mal_{factor}"] = lambda df: df["x"] * factor
df = df.assign(**results)
print(df)
# Überraschung: Alle drei Spalten multiplizieren mit 30!
# Lambdas speichern die Variable „factor", nicht deren Wert.
# Nach der Schleife ist factor = 30.
Die pd.col()-Lösung
import pandas as pd
df = pd.DataFrame({
"preis": [10.0, 25.0, 15.0],
"menge": [3, 1, 5],
"temp_c": [0, 20, 100]
})
# Vorher — mit Lambda
df_alt = df.assign(
gesamt=lambda x: x["preis"] * x["menge"]
)
# Nachher — mit pd.col()
df_neu = df.assign(
gesamt=pd.col("preis") * pd.col("menge")
)
# Auch String-Methoden funktionieren
df2 = pd.DataFrame({"stadt": ["berlin", "münchen", "hamburg"]})
df2 = df2.assign(stadt_gross=pd.col("stadt").str.upper())
print(df2)
# Ausgabe:
# stadt stadt_gross
# 0 berlin BERLIN
# 1 münchen MÜNCHEN
# 2 hamburg HAMBURG
# Temperaturumrechnung
df = df.assign(temp_f=pd.col("temp_c") * 9/5 + 32)
print(df[["temp_c", "temp_f"]])
# Ausgabe:
# temp_c temp_f
# 0 0 32.0
# 1 20 68.0
# 2 100 212.0
Deutlich lesbarer als die Lambda-Variante, oder?
Einschränkungen von pd.col()
pd.col() funktioniert überall dort, wo ein Callable akzeptiert wird — also in DataFrame.assign(), DataFrame.loc() und mehr. Eine wichtige Einschränkung gibt es allerdings: In GroupBy-Operationen kann pd.col() noch nicht verwendet werden. Das soll in zukünftigen Versionen kommen, aber Stand jetzt müssen Sie dort weiterhin mit Lambda oder String-Aliasen arbeiten.
Datetime-Auflösung: Von Nanosekunden zu Mikrosekunden
In früheren Versionen hat pandas Datetime-Daten standardmäßig mit Nanosekunden-Auflösung gespeichert. Das klingt erstmal nach „mehr Genauigkeit = besser", führte aber zu einem nervigen Problem: Datumsangaben vor dem Jahr 1678 oder nach 2262 konnten nicht dargestellt werden und erzeugten einen OutOfBoundsDatetime-Fehler. Wer jemals mit historischen Daten gearbeitet hat, kennt diesen Schmerz.
Ab pandas 3.0 ist die Standard-Auflösung Mikrosekunden (oder die Auflösung des Inputs). Damit wird der darstellbare Datumsbereich massiv erweitert:
import pandas as pd
# pandas < 3.0 — OutOfBoundsDatetime-Fehler!
# pd.Timestamp("1600-01-01")
# pandas 3.0 — funktioniert problemlos
ts = pd.Timestamp("1600-01-01")
print(ts)
# Ausgabe: 1600-01-01 00:00:00
# Auflösung prüfen
ser = pd.Series(pd.to_datetime(["2026-01-01", "2026-06-15"]))
print(ser.dtype)
# Ausgabe: datetime64[us] (Mikrosekunden statt ns)
Falls Sie aus irgendeinem Grund weiterhin Nanosekunden-Auflösung brauchen, können Sie diese explizit angeben:
# Explizite Nanosekunden-Auflösung
ser = pd.Series(pd.to_datetime(["2026-01-01"]).as_unit("ns"))
print(ser.dtype)
# Ausgabe: datetime64[ns]
Entfernte Funktionen und APIs
Pandas 3.0 hat ordentlich aufgeräumt und zahlreiche Funktionen entfernt, die schon länger als deprecated markiert waren. Hier sind die wichtigsten, die Sie kennen sollten:
Entfernte Methoden und Parameter
DataFrame.last()undSeries.last()— entferntCategorical.to_list()— verwenden Sie stattdessen.tolist()methodundlimitParameter inNDFrame.replace()— entferntobjArgument inGroupBy.get_group()— entfernt- Direkte JSON-Strings an
read_json()— verwenden Sieio.StringIO()
Entfernte Zeiteinheiten-Aliase
Mehrere veraltete Offset-Aliase wurden entfernt und durch ihre vollständigen Äquivalente ersetzt. Diese Änderung ist schnell gemacht, aber man muss halt erstmal wissen, dass sie nötig ist:
'H'→'h'(Stunden)'T'/'t'→'min'(Minuten)'S'→'s'(Sekunden)'L'/'l'→'ms'(Millisekunden)'U'→'us'(Mikrosekunden)'N'→'ns'(Nanosekunden)
import pandas as pd
# Vorher (veraltet)
# pd.date_range("2026-01-01", periods=5, freq="T")
# Nachher (korrekt)
pd.date_range("2026-01-01", periods=5, freq="min")
Verhaltensänderungen bei GroupBy
Ein Detail, das leicht übersehen wird: Wenn Sie nach einer Liste mit nur einem Element gruppieren, gibt die Iteration jetzt Tupel der Länge 1 zurück — statt wie bisher einzelne Werte:
import pandas as pd
df = pd.DataFrame({"a": [1, 1, 2], "b": [10, 20, 30]})
# pandas 3.0: Tupel der Länge 1
for key, group in df.groupby(["a"]):
print(type(key), key)
# Ausgabe:
# <class 'tuple'> (1,)
# <class 'tuple'> (2,)
Neue Deprecation-Policy
Pandas 3.0 führt eine neue 3-stufige Deprecation-Policy ein, die Downstream-Paketen (und uns allen) mehr Zeit für Anpassungen gibt:
- Stufe 1:
DeprecationWarning— nur für Entwickler sichtbar (standardmäßig unterdrückt) - Stufe 2:
FutureWarning— für alle Nutzer sichtbar, in der letzten Minor-Version vor dem nächsten Major-Release - Stufe 3: Entfernung im nächsten Major-Release
Das ist eine wirklich gute Änderung. Wenn Sie Ihren Code regelmäßig gegen die neueste Minor-Version testen und Warnungen beheben, sollten zukünftige Major-Upgrades deutlich reibungsloser verlaufen. Kein „Oh nein, alles ist kaputt" mehr am Upgrade-Tag.
Praxis-Checkliste: Ihr pandas 3.0 Upgrade in 7 Schritten
Zum Abschluss hier nochmal alles kompakt zusammengefasst. Am besten arbeiten Sie diese Liste der Reihe nach ab:
- Python-Version prüfen — Stellen Sie sicher, dass Python 3.11+ installiert ist
- Auf pandas 2.3 upgraden — Beheben Sie alle Deprecation-Warnungen
- PyArrow installieren —
pip install pyarrowfür die beste String-Performance - Chained Assignment ersetzen — Suchen Sie nach Mustern wie
df["col"][mask] = ...und ersetzen Sie sie durchdf.loc[mask, "col"] = ... - Dtype-Prüfungen aktualisieren — Ersetzen Sie
dtype == "object"durchpd.api.types.is_string_dtype() - Offset-Aliase aktualisieren — Ersetzen Sie veraltete Kürzel (H, T, S, L, U, N) durch die neuen (h, min, s, ms, us, ns)
- Tests ausführen — Führen Sie Ihre gesamte Testsuite aus und prüfen Sie die Ergebnisse sorgfältig
FAQ — Häufig gestellte Fragen zu pandas 3.0
Ist pandas 3.0 abwärtskompatibel?
Kurze Antwort: Nein, nicht vollständig. Pandas 3.0 enthält mehrere Breaking Changes, allen voran Copy-on-Write als Standard, den neuen String-Datentyp und die Entfernung vieler veralteter Funktionen. Deshalb empfiehlt das Entwicklerteam dringend, zuerst auf pandas 2.3 zu upgraden und alle Deprecation-Warnungen zu beheben, bevor der Sprung auf 3.0 erfolgt.
Brauche ich PyArrow für pandas 3.0?
Zwingend erforderlich ist es nicht, aber Sie sollten es wirklich installieren. Ohne PyArrow fällt der neue String-Datentyp auf den langsameren NumPy-object-Dtype zurück. Mit PyArrow bekommen Sie bis zu 5–10x bessere Performance bei der Verarbeitung von Text-Daten und profitieren vom effizienteren Speicherformat.
Was passiert mit meinem bestehenden Code, der .copy() verwendet?
Gute Nachricht: Bestehende .copy()-Aufrufe sind weiterhin gültig — sie sind nur nicht mehr nötig. Da Copy-on-Write jetzt Standard ist, verhält sich jedes Subset automatisch wie eine Kopie. Sie können die überflüssigen .copy()-Aufrufe nach und nach entfernen, um Ihren Code aufzuräumen.
Kann ich pandas 2.x und 3.0 parallel verwenden?
In derselben Python-Umgebung kann nur eine pandas-Version installiert sein. Für eine sichere Migration empfiehlt es sich, mit virtuellen Umgebungen zu arbeiten: Erstellen Sie eine neue Umgebung mit pandas 3.0, testen Sie dort Ihren Code, und wechseln Sie erst, wenn alles grün ist.
Funktioniert pd.col() mit GroupBy-Operationen?
Leider noch nicht. In pandas 3.0 können pd.col()-Ausdrücke noch nicht in GroupBy-Operationen verwendet werden. Das soll in zukünftigen Versionen kommen. Für GroupBy-Aggregationen nutzen Sie vorerst weiterhin die bisherige Syntax mit String-Aliasen oder Lambda-Funktionen.