ESPNFrom superstar signings to under-the-radar finds: How each of MLB's four remaining teams were builtPunchSupreme Court delivered 411 judgments in one year – CJNThe Jerusalem PostIDF probes suspected negligence after officer killed in Humvee accident in southern LebanonESPN DeportesEx presidente Barça: Que Messi se despidaRTP Desporto12h30 Históricos de Betis e Lens anteveem Porto e SportingBollywood HungamaRian Mukherjee wins Best Child Actor at Los Angeles Film Awards 2026 for Hindi film ManzilZDF heuteEntdecken Sie das ZDF-NachrichtenstudioIl Fatto Quotidiano“Barbara D’Urso porterà a casa circa 200 mila euro complessivi, cioè 15 mila euro a puntata”: ecco il cachet della giurata di “Ballando con le stelle”CBS NewsSaudi airport stays shut as Houthi attacks kill 20 people in a week7sur7Toute attaque contre l’Otan serait “totalement vaine”, assure son chefWirtualna PolskaTusk o policji w szkołach. "Tak, jesteśmy przeczuleni"RTL BoulevardTennisser Van de Zandschulp boekt in Shanghai knappe zege op Fils
The Daily Newsstand · Free, Always
Monday, October 12, 2026

Python 3.15 erschienen: Faule Importe, UTF-8 und neue Datentypen

Translate

Python 3.15.0 ist verfügbar. Die neue Hauptversion der Programmiersprache erschien am 9. Oktober 2026 und bringt Änderungen an der Sprache, am Referenzinterpreter CPython und an der Standardbibliothek. Zu den auffälligsten Neuerungen gehören explizit verzögerte Imports (Lazy Imports) sowie die eingebauten Typen frozendict und sentinel. Hinzu kommen Fortschritte beim experimentellen Just-in-time-Compiler.

Laut Release Notes von Python 3.15.0 flossen 5643 Commits von 1012 Mitwirkenden in die Version ein. Die Freigabe verzögerte sich um eine Woche. Am 2. Oktober schob Release-Manager Hugo van Kemenade einen dritten Release Candidate nach, weil kurz vor Schluss bei den Lazy Imports noch Fehler aufgetaucht waren, die eine Freigabe blockierten.

Ein Import lädt ein Modul und führt dabei dessen Code aus. Bei umfangreichen Abhängigkeiten kann das schon die Hilfeausgabe eines Kommandozeilenprogramms verzögern.

Python 3.15 ergänzt dafür das weiche Schlüsselwort lazy. Weich heißt: Es hat nur vor einer Importanweisung eine besondere Bedeutung und bleibt sonst als Name verwendbar. Ein so gekennzeichneter Import verschiebt das Laden bis zur ersten Verwendung des importierten Namens. Ein vereinfachtes Beispiel für ein Werkzeug mit optionaler JSON-Ausgabe:

# Python 3.15
lazy import json
import sys

def main():
    if "--json" in sys.argv:
        print(json.dumps({"status": "ok", "version": "3.15"}))
    else:
        print("Status: ok")

if __name__ == "__main__":
    main()

Ohne die Option --json benötigt dieses Programm das Modul json nicht. Erst beim Zugriff auf json.dumps wird der verzögerte Import aufgelöst. In einer eigenen Messung brauchte ein Skript, das 13 Module der Standardbibliothek importiert und dann nur eine Zeile ausgibt, auf einem Apple M4 mit gewöhnlichen Imports im Median 44 Millisekunden. Mit lazy waren es 11, kaum mehr als bei einem Skript ganz ohne Imports.

lazy ist nur auf Modulebene erlaubt, also auf der obersten Ebene einer Datei, nicht in Funktionen, Klassen oder try-Blöcken, und nicht für import *. Wer bestehenden Code ohne Umschreiben testen will, kann mit der Umgebungsvariablen PYTHON_LAZY_IMPORTS=all nahezu alle Imports auf Modulebene verzögern.

Das Verfahren verändert allerdings den Zeitpunkt von Seiteneffekten und Fehlern. Ein fehlendes Modul fällt erst beim ersten Zugriff auf.

Ein Wörterbuch (dict) ordnet Schlüsseln Werte zu. Mit frozendict gibt es davon nun eine unveränderliche Variante. Einträge lassen sich nach der Erstellung weder hinzufügen noch entfernen oder ersetzen. Das schützt etwa gemeinsam verwendete Konfigurationen vor versehentlichen Änderungen:

# Python 3.15
config = frozendict({
    "host": "localhost",
    "port": 8000,
    "debug": False,
})

print(config["port"])  # 8000

# Löst TypeError aus: 'frozendict' object does not support item assignment
# config["port"] = 9000

Die Unveränderlichkeit betrifft nur die Zuordnung. Eine enthaltene Liste bleibt veränderlich. Sind auch alle Werte hashbar, also ihrerseits unveränderlich wie Zahlen und Zeichenketten, ist auch das frozendict hashbar. Es taugt dann selbst als Schlüssel eines Wörterbuchs oder als Element einer Menge. Beim Vergleich zweier frozendict spielt die Reihenfolge der Einträge keine Rolle.

Neu ist die Idee nicht, denn ein erster Vorschlag für frozendict wurde 2012 abgelehnt, unter anderem weil der Bedarf als gering galt. Die Autoren des neuen Anlaufs, Victor Stinner und Donghee Na, verweisen darauf, dass Programme heute häufiger Daten zwischen gleichzeitig laufenden Teilen austauschen: 2014 kam asyncio hinzu, 2024 eine Interpretervariante ohne Global Interpreter Lock (GIL), in der Threads mehrere Prozessorkerne gleichzeitig nutzen, 2025 das Modul concurrent.interpreters für mehrere Interpreter in einem Prozess. Ein unveränderliches Wörterbuch lässt sich zwischen Threads ohne Sperren weiterreichen. Den Bedarf belegen für sie die Pakete frozendict und frozenmap im Paketverzeichnis PyPI.

Mit frozendict fällt im Alltag ein versehentlicher Schreibzugriff auf Konfigurationen, Nachschlagetabellen oder Standardwerte von Funktionen sofort als Fehler auf, statt unbemerkt andere Programmteile zu beeinflussen. Außerdem taugt ein frozendict als Argument für Caches wie functools.lru_cache (siehe Dokumentation zu lru_cache), die Ergebnisse aufwendiger Berechnungen aufheben und dafür hashbare Argumente verlangen. Ein dict führt dort zum Fehler.

Mehr Tempo als ein dict verspricht der neue Typ nicht, er teilt den größten Teil seines Codes mit ihm.

Der neue eingebaute Typ sentinel löst ein häufiges API-Problem: Eine Funktion soll unterscheiden können, ob ein Argument fehlt oder ausdrücklich None, Pythons Wert für „nichts“, übergeben wurde. Dafür braucht es einen Markerwert (Sentinel), der mit keinem echten Wert verwechselt werden kann. Bisher dient dazu oft ein eigens erzeugtes object(), das in Funktionssignaturen und in der Hilfe nichtssagend als <object object at 0x...> erscheint. Python 3.15 bietet mit den Sentinel Values eine benannte Alternative:

# Python 3.15
MISSING = sentinel("MISSING")

def describe(value=MISSING):
    if value is MISSING:
        return "Kein Wert übergeben"
    if value is None:
        return "Explizit None übergeben"
    return f"Wert: {value!r}"

print(describe())       # Kein Wert übergeben
print(describe(None))   # Explizit None übergeben
print(describe(0))      # Wert: 0

Der Vergleich erfolgt mit is, das prüft, ob zwei Namen dasselbe Objekt bezeichnen. Jeder Aufruf von sentinel() erzeugt ein neues Objekt, auch bei identischem Namen. Gemeinsam verwendete Marker müssen deshalb einmal definiert und wiederverwendet werden. Kopien liefern dasselbe Objekt zurück, und ein Sentinel, der unter seinem Namen aus einem Modul importierbar ist, behält seine Identität auch beim Serialisieren mit pickle.

Die im Alltag möglicherweise folgenreichste Änderung kommt ohne neue Syntax aus. Python 3.15 aktiviert den UTF-8-Modus standardmäßig. Textoperationen ohne ausdrücklich angegebene Kodierung verwenden dadurch UTF-8, statt sich nach den Sprach- und Regionseinstellungen des Systems (Locale) zu richten. Das betrifft insbesondere bestehende Programme unter Windows, die bisher implizit eine lokale Kodierung voraussetzen.

Vorhandene Dateien werden durch die Änderung nicht umkodiert. Eine ältere Datei mit Windows-1252-Daten muss weiterhin entsprechend eingelesen werden:

with open("altbestand.csv", encoding="cp1252") as file:
    text = file.read()

Wer weiterhin die Kodierung des Systems braucht, gibt encoding="locale" an. Der UTF-8-Modus lässt sich außerdem mit PYTHONUTF8=0 oder -X utf8=0 abschalten. Der zugrunde liegende Änderungsvorschlag PEP 686 (Python Enhancement Proposal) empfiehlt, implizite Kodierungsannahmen vor der Umstellung aufzuspüren: Mit -X warn_default_encoding meldet der Interpreter jedes open() ohne encoding-Argument als EncodingWarning.

Beim Upgrade gehören reale Import- und Exportdaten in die Prüfung. Tests mit ausschließlich ASCII-Zeichen können bestehen, obwohl Umlaute in einer älteren Datei Probleme verursachen.

Comprehensions sind Pythons Kurzschreibweise, um eine Liste, eine Menge oder ein Wörterbuch in einem Ausdruck aus einer Schleife zu erzeugen. Sie und die verwandten Generatorausdrücke können jetzt entpacken: * führt mehrere Listen oder Mengen zu einer zusammen, ** mehrere Wörterbücher:

# Python 3.15
batches = [[1, 2], [3], [4, 5]]

flat = [*batch for batch in batches]
print(flat)  # [1, 2, 3, 4, 5]

groups = [{"python", "linux"}, {"python", "windows"}]
all_tags = {*group for group in groups}
print(sorted(all_tags))  # ['linux', 'python', 'windows']

Bisher war für die flache Liste eine Comprehension mit zwei Schleifen nötig:

flat = [item for batch in batches for item in batch]

Auch mehrere Konfigurationsebenen lassen sich kompakt kombinieren:

# Python 3.15
layers = [
    {"host": "localhost", "port": 8000},
    {"port": 9000},
    {"debug": True},
]

config = {**layer for layer in layers}
print(config)
# {'host': 'localhost', 'port': 9000, 'debug': True}

Bei mehrfach vorkommenden Schlüsseln gewinnt der später verarbeitete Wert. Python 3.14 lehnt beide Schreibweisen mit einem Syntaxfehler ab.

Profiler messen, wo ein Programm seine Laufzeit verbringt. Python ordnet seine eingebauten Werkzeuge dafür neu. Das Paket profiling bündelt unterschiedliche Verfahren unter einem gemeinsamen Namen. profiling.tracing übernimmt das deterministische Profiling aus cProfile; profiling.sampling enthält den neuen statistischen Profiler Tachyon (Dokumentation zu profiling.sampling). cProfile bleibt als Alias verfügbar. Das Modul profile ist veraltet und soll mit Python 3.17 entfernt werden.

Tracing verfolgt Funktionsaufrufe und liefert genaue Aufrufzahlen. Sampling nimmt Stichproben des Aufrufstapels, um zeitintensive Programmstellen zu finden. Tachyon tut das standardmäßig 1000-mal pro Sekunde und kann ein Skript starten oder sich an einen laufenden Python-Prozess hängen, ohne dass dieser neu gestartet oder verändert werden muss. Weil der Profiler dazu den Speicher des anderen Prozesses liest, braucht er meist Root- oder Administratorrechte:

sudo python3.15 -m profiling.sampling run analyse.py
sudo python3.15 -m profiling.sampling attach 12345

Ein interaktiver Flame-Graph zeigt als HTML-Datei, welchen Anteil der Laufzeit jede Funktion samt der von ihr aufgerufenen Funktionen beansprucht:

sudo python3.15 -m profiling.sampling run \
  --flamegraph -o profile.html analyse.py

Sehr kurze Funktionsaufrufe können zwischen zwei Stichproben liegen und unbemerkt bleiben. Wer exakte Aufrufzahlen benötigt, bleibt beim Tracing.

Auch der experimentelle Just-in-time-Compiler (JIT) wurde überarbeitet. Er übersetzt häufig durchlaufenen Python-Code zur Laufzeit in Maschinencode. Wo ein Build ihn enthält, ist er abgeschaltet und lässt sich mit der Umgebungsvariablen PYTHON_JIT=1 aktivieren. Die offizielle Dokumentation nennt für die Benchmark-Suite pyperformance im geometrischen Mittel einen Leistungsvorteil von 7 bis 8 Prozent gegenüber dem vollständig optimierten Standardinterpreter auf x86-64-Linux. Auf AArch64-macOS, also Macs mit Apple-Prozessor, sind es 11 bis 12 Prozent gegenüber dem Tail-Calling-Interpreter. Der setzt seit Python 3.14 jede Bytecode-Anweisung als eigene kleine C-Funktion um.

Diese Zahlen sind keine pauschale Beschleunigung gegenüber Python 3.14. Sie vergleichen JIT- und Nicht-JIT-Konfigurationen unter bestimmten Bedingungen. Die Ergebnisse einzelner Benchmarks reichen laut Dokumentation von ungefähr 15 Prozent Verlangsamung bis zu mehr als 100 Prozent Beschleunigung, den Mikrobenchmark unpack_sequence ausgenommen.

Zu den Änderungen gehören ein neues Tracing-Frontend, das tatsächlich durchlaufene Pfade aufzeichnet, statt sie zu schätzen, und eine einfache Registerallokation, die Zwischenwerte in Prozessorregistern hält statt im Speicher.

Unabhängig vom JIT profitiert Windows: Die offiziellen 64-Bit-Binaries verwenden jetzt ebenfalls den Tail-Calling-Interpreter, den erst der Compiler aus Visual Studio 2026 ermöglicht. Das Python-Team misst damit auf pyperformance 15 bis 20 Prozent mehr Tempo als mit dem bisherigen Interpreter.

Wer die Neuerungen spielerisch erkunden will: Der langjährige Python-Entwickler Barry Warsaw hat mit whatsnewt ein englischsprachiges Text-Adventure fürs Terminal geschrieben (siehe Abb. 1). Jedes der 18 Rätsel verlangt ein paar Zeilen Code mit einer Neuerung aus 3.15, die das Spiel tatsächlich ausführt. Mit dem Paketmanager uv genügt zum Start ein Befehl, der Spiel und passendes Python bei Bedarf herunterlädt:

uvx --python 3.15 whatsnewt

Das Text-Adventure von Python 3.15

Die Neuerungen von Python 3.15 lassen sich auch spielerisch per Text-Adventure erkunden (Abb. 1).

Mac-Anwender sollten vor dem Wechsel auf macOS 27.0 einen Hinweis der Release-Seite beachten: Die mitgelieferte Entwicklungsumgebung IDLE und andere Programme mit Tkinter-Oberfläche können dort beim Öffnen von Dialogen aus dem Menü hängen bleiben. Ursache ist demnach eine Verhaltensänderung des Betriebssystems, kein Fehler in Python 3.15. Betroffen sind daher alle aktuellen Python-Versionen. Laut CPython-Issue 158053 ist ein Workaround bereits in die Tk-Entwicklungszweige eingeflossen; ein Python-Update mit korrigiertem Tk steht noch aus.

Als praktische Vorgehensweise bietet sich eine separate Testumgebung an, in der neben den regulären Tests typische Start-, Import- und Exportvorgänge laufen. Bei Lazy Imports gehören Initialisierungen und Registrierungen in die Prüfung, bei in C oder Rust geschriebenen Erweiterungsmodulen die Unterstützung für die gewählte Interpretervariante, etwa die ohne GIL. Die offiziellen macOS-Binaries installieren diese Free-Threading-Variante jetzt standardmäßig mit.

Neue Syntax muss außerdem zur erklärten Mindestversion eines Projekts passen. Wer weiterhin Python 3.14 oder ältere Versionen unterstützt, kann lazy-Imports und entpackende Comprehensions nicht in gemeinsam genutzte Quelldateien übernehmen.

Für die 3.15-Reihe sieht der Veröffentlichungsplan ungefähr zweimonatliche Fehlerkorrekturversionen über zwei Jahre vor. Anschließend sollen noch rund drei Jahre Sicherheitsaktualisierungen als Quellcode folgen, bis ungefähr Oktober 2031.

View the original on heise online →

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.