- Stellt 14 wenig bekannte fortgeschrittene Funktionen in Python anhand praktischer Beispiele vor
- Bietet eine tiefgehende Erklärung zu statischer Typisierung und strukturellem Design wie
typing, generics, protocols und context managers
- Enthält außerdem strukturelles Pattern Matching, das ab Python 3.10 neu eingeführt wurde, sowie Performance-Optimierungstechniken wie Slots und Metaklassen
- Beinhaltet Tipps für saubereren Code wie
f-string, cache, future, proxy, for-else und walrus
- Zu jeder Funktion gibt es Links und Referenzmaterial für weiterführendes Lernen, mit einer Struktur, die auch für Junior-Entwickler leicht zugänglich ist
Zusammenfassung von 14 fortgeschrittenen Python-Funktionen
# Typing-Overload
- Der Decorator
@overload ermöglicht es, mehrere Typsignaturen für eine einzelne Funktion zu definieren
- Type-Checker können abhängig von den übergebenen Argumentwerten den Rückgabetyp präzise ableiten
- Mit
Literal lässt sich auch eine Einschränkung auf bestimmte String-Werte umsetzen
- Es lassen sich auch Funktionssignaturen implementieren, die genau eines von
id oder username verlangen
Literal kann als leichtgewichtige Enum-Alternative für Typsicherheit genutzt werden
# Keyword-only-/Positional-only-Argumente
- Mit
* lassen sich Keyword-only-Argumente festlegen (Positionsargumente sind nicht erlaubt)
- Mit
/ lassen sich Positional-only-Argumente festlegen (Keyword-Argumente sind nicht erlaubt)
- Beim API-Design kann damit die Verwendung von Argumenten klar erzwungen werden
# Future-Annotationen (__future__)
- Da Type Hints ursprünglich zur Laufzeit sofort ausgewertet werden, entstehen Probleme mit der Reihenfolge von Deklarationen
- Mit
from __future__ import annotations lässt sich der Zeitpunkt der Auswertung verzögern
- Da dies jedoch auf String-Verarbeitung basiert, ist bei der Verwendung von Typen zur Laufzeit Vorsicht geboten
PEP 649 schlägt eine Verbesserung durch verzögerte Auswertung über das Attribut __annotations__ vor
# Generic-Syntax
- Ab Python 3.12 wird eine neue Syntax zur Definition generischer Typen unterstützt
- Statt
TypeVar ist eine intuitivere Form wie class Foo[T, U: int] möglich
- Auch Variadic Generics wurden eingeführt und erlauben die Verarbeitung verschiedener Typen
- Die Definition von Type Aliases wurde ebenfalls vereinfacht, etwa in der Form
type Vector = list[float]
# Protocols
- Als typisierte Variante von Duck Typing lässt sich strukturelles Subtyping umsetzen
- Wenn eine Klasse bestimmte Methoden besitzt, ist Typkompatibilität auch ohne Type-Vererbung möglich
- Mit
@runtime_checkable lässt sich dies auch auf isinstance-Prüfungen erweitern
# Context Manager
- Objekte mit den Methoden
__enter__ und __exit__ werden in with-Blöcken verwendet
- Mit dem Decorator
contextlib.contextmanager ist eine einfache funktionsbasierte Implementierung möglich
- Rund um
yield werden Setup- und Cleanup-Arbeiten ausgeführt
# Strukturelles Pattern Matching
- Mit der Syntax
match-case lassen sich komplexe Datenstrukturen intuitiv verzweigen und verarbeiten
- Tupel-/Listen-Destrukturierung, OR-Patterns, Guard-Bedingungen (
if) und Wildcards sind möglich
- Da Verzweigungen anhand der Struktur von Daten erfolgen, werden Lesbarkeit und Wartbarkeit verbessert
# __slots__-Optimierung
- Durch die Verwendung fester Slots statt
__dict__ werden Speicherverbrauch und Geschwindigkeit optimiert
__slots__ verwendet ein Tupel, das nur Attributnamen enthält
- Verhindert das Hinzufügen unnötiger Attribute zu Klassen
- Allerdings handelt es sich um eine Mikro-Optimierung, daher ist ein überlegter Einsatz nötig
# Sammlung von Python-Code-Style-Tipps
- for-else-Konstrukt:
else wird ausgeführt, wenn die Schleife ohne break endet
- Walrus-Operator (
:=): Variablendeklaration und Prüfung gleichzeitig möglich
- Kurzschlussauswertung mit
or: Gibt unter mehreren Werten den ersten wahrheitsgemäßen zurück
- Verkettung von Vergleichsoperatoren: Mit
0 < x < 10 lässt sich Code kompakter schreiben
# Fortgeschrittenes f-string-Formatting
- Mit der Syntax
f"{변수=}" sind Ausgaben für Debugging-Zwecke möglich
- Verschiedene Optionen wie Zahlenformatierung (
:.2f, :+.2f, :,) und Datumsformatierung (%Y-%m-%d) werden unterstützt
- Auch Format-Mini-Sprache wie Zentrierung, Padding und Prozentdarstellung kann genutzt werden
# Cache-Decorator
- Mit
@lru_cache und @cache werden Funktionsergebnisse gespeichert, um die Geschwindigkeit zu erhöhen
- Besonders nützlich bei rekursiven Funktionen oder häufig wiederholten Berechnungen
@cache wurde ab Python 3.9 eingeführt und bietet standardmäßig unbegrenzten Cache
# Python Future
- Eine Funktion zur Verarbeitung asynchroner Objekte, ähnlich wie Promises in JS
- Mit
Future.set_result() und add_done_callback() lassen sich Ergebnisse asynchron verwalten
asyncio.Future() kann zusammen mit await verwendet werden
- In Verbindung mit
ThreadPoolExecutor ist auch parallele Verarbeitung im Hintergrund möglich
# Proxy-Property
- Erlaubt, dass ein einzelnes Klassenattribut sowohl wie ein Attribut als auch wie eine Funktion funktioniert
- Über
__get__, __call__ und __repr__ werden beide Funktionen bereitgestellt
- Beim API-Design können so Standardwerte und parameterisierte Aufrufe in einer einzigen Form behandelt werden
- Eher als experimentelles Beispiel interessant als für den praktischen Einsatz
# Metaklassen
- Die Klasse einer Klasse, die Klassen selbst erzeugt
- Ermöglicht Meta-Logik wie das Manipulieren von Klassenattributen oder automatische Registrierung
- In der Praxis meist durch Decorators ersetzbar
- In Django, SQLAlchemy und Pydantic werden Metaklassen intern verwendet
5 Kommentare
Aus Backend-Sicht habe ich die Erfahrung gemacht, dass Metaklassen das Debugging erschweren.
Beachten Sie, dass
for-elsehäufig als Anti-Pattern gilt, da es nach Ansicht vieler weder die Lesbarkeit noch die Klarheit erhöht, und dassasyncio.Futureals internes Implementierungsdetail vonasynciobetrachtet wird.Danke. Insbesondere Punkt 10 setze ich sofort um.
AI-Coding-Regeln hinzugefügt..
Danke für den tollen Tipp.
Hacker-News-Kommentare
Hallo! Ich bin der Originalautor des Blogposts! Ich war überrascht, als ich um 4 Uhr morgens sah, dass mein Beitrag auf der HN-Startseite gelandet war
Jedes Mal, wenn ich Python benutze, mache ich mir Sorgen, ob mein Code so aussieht, als würde ich Python falsch verwenden
Python sollte Python bleiben, und golang, Rust und Typescript sollten jeweils ihre eigene Philosophie und ihr eigenes Design haben
Der größte Vorteil von Python ist, dass es sich wie ausführbarer Pseudocode anfühlt
Hinweis zu Abschnitt 9.3 Auswertung: Bei einem leeren String fällt die Auswertung anders aus
Als jemand, der von Javascript/Typescript zu Python gewechselt ist, ist das eine nützliche Ressource
Die meisten Features sind keine Advanced Features
Was ich an der Liste ändern würde, ist die Aufnahme von collections.abc-Containern
Es hat Spaß gemacht, diesen Artikel zu lesen