
Jedes
@property, classmethod, staticmethod und sogar der Aufruf gewöhnlicher Methoden funktioniert unter der Haube mit demselben Mechanismus. Mit Deskriptoren. Ein Deskriptor ist jede Klasse, die mindestens eine der Protokollmethoden implementiert:
__get__, __set__ oder __delete__. Sobald Sie eine Instanz einer solchen Klasse an ein Attribut einer anderen Klasse binden, übernimmt Python die Kontrolle über den Zugriff.1️⃣ Prioritätshierarchie
Wenn Sie
obj.attr schreiben, greift Python nicht einfach in das Wörterbuch. Es folgt einer strengen Kette:▪️ Data Descriptor (definiert
__set__ oder __delete__). Er hat absolute Priorität. Wenn der Attributname von einem Data-Deskriptor abgefangen wird, ignoriert Python instance.__dict__. Deshalb können Sie @property nicht durch eine einfache Zuweisung überschreiben (wenn kein Setter vorhanden ist).▪️ Instanzwörterbuch (
__dict__). Normale Objektdaten.▪️ Non-Data Descriptor (nur
__get__ definiert). Gewöhnliche Klassenmethoden sind genau das. Sie liegen am Ende der Prioritäten. Wenn Sie manuell eine Funktion mit dem Methodennamen in __dict__ des Objekts ablegen, überschreibt diese die ursprüngliche Methode. 2️⃣ Shared State Anti-pattern
Ein Deskriptor wird auf Klassenebene initialisiert, nicht auf Instanzebene. Er ist für alle gleich. Wenn Sie Daten innerhalb der Deskriptorinstanz speichern, überschreiben Sie diesen Wert für alle Objekte Ihrer Klasse. Wenn Vasya das Alter ändert, wird Petja plötzlich mit ihm altern, weil beide Instanzen auf dieselbe Speicherzelle des Deskriptors zugreifen.
Wie schreibt man es richtig?
Der Zustand muss strikt im Wörterbuch der Instanz selbst gespeichert werden. Um keine Krücken zu schreiben, wurde in Python 3.6+ die magische Methode
__set_name__ eingeführt. Sie ermöglicht es dem Deskriptor, den Namen zu erfahren, unter dem er in der Klasse erstellt wurde, um die Daten legal im __dict__ des jeweiligen Objekts zu speichern.class Validator:
def __set_name__(self, owner, name):
# Merken des Attributnamens, um nicht hardcoden zu müssen
self.private_name = f"_{name}"
def __get__(self, instance, owner):
if instance is None:
return self
return getattr(instance, self.private_name)
def __set__(self, instance, value):
# ✅ Daten nur in das Wörterbuch der KONKRETEN Instanz schreiben
if not isinstance(value, int):
raise TypeError("Nur ganze Zahlen erlaubt")
setattr(instance, self.private_name, value)
class User:
age = Validator() # age_validator.__set_name__ erhält name='age'Deskriptoren sind ein mächtiges Werkzeug zur Kapselung von Logik. Die ganze Magie von Frameworks wie Django oder SQLAlchemy basiert auf ihnen ☝️
#anatomie_des_python
Kommentare
0Noch keine Kommentare.