0Pricing
Python Academy · Lektion

Deskriptoren: __get__, __set__, __delete__

Implementieren Sie das Deskriptorprotokoll zur Steuerung des Attributzugriffs.

Deskriptoren: __get__, __set__, __delete__ ist eine kostenlose Python Academy-Lektion auf CoddyKit. Dies ist Lektion 3 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Python Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Python Academy-Kurs umfasst insgesamt 4 Lektionen.

Was ist ein Deskriptor?

Ein Deskriptor ist ein Objekt, das __get__, __set__ oder __delete__ definiert und als Klassenattribut zugewiesen wird. Python ruft diese Methoden beim Zugriff auf das Attribut auf.

class Descriptor:
    def __get__(self, obj, objtype=None):
        print(f"__get__ called, obj={obj}")
        return 42

class MyClass:
    attr = Descriptor()

print(MyClass().attr)   # __get__ called ... 42

Daten- vs. Nicht-Daten-Deskriptoren

Daten-Deskriptoren definieren __set__ oder __delete__ und haben Vorrang vor dem __dict__ der Instanz. Nicht-Daten-Deskriptoren (nur __get__) geben dem __dict__ den Vorrang.

class DataDesc:
    def __get__(self, obj, t): return "data"
    def __set__(self, obj, val): pass

class NonDataDesc:
    def __get__(self, obj, t): return "nondata"

class C:
    d = DataDesc()
    n = NonDataDesc()

c = C()
c.__dict__["n"] = "instance"  # shadows the non-data desc
c.__dict__["d"] = "instance"  # does NOT shadow data desc
print(c.n)   # instance
print(c.d)   # data

__get__-Signatur

__get__(self, obj, objtype): obj ist die Instanz (oder None, wenn der Zugriff über die Klasse erfolgt), objtype ist die Klasse.

class Verbose:
    def __get__(self, obj, objtype=None):
        if obj is None:
            return self   # accessed on class
        return f"value for {obj!r}"

class Widget:
    label = Verbose()

print(Widget.label)        # <Verbose object>
print(Widget().label)      # value for <Widget object>

__set__ und Validierung

Implementieren Sie __set__(self, obj, value), um einen Wert vor dem Speichern zu validieren oder umzuwandeln.

class PositiveInt:
    def __set_name__(self, owner, name):
        self.name = name

    def __get__(self, obj, t):
        return obj.__dict__.get(self.name)

    def __set__(self, obj, val):
        if not isinstance(val, int) or val <= 0:
            raise ValueError(f"{self.name} must be a positive int")
        obj.__dict__[self.name] = val

class Rect:
    width  = PositiveInt()
    height = PositiveInt()

r = Rect()
r.width = 10
# r.width = -1  # ValueError

__set_name__

Python 3.6+ ruft __set_name__(owner, name) am Deskriptor auf, wenn dieser einer Klasse zugewiesen wird. Dadurch erhält der Deskriptor Zugriff auf seinen eigenen Attributnamen.

class Typed:
    def __set_name__(self, owner, name):
        self.public  = name
        self.private = "_" + name

    def __get__(self, obj, t):
        return None if obj is None else getattr(obj, self.private, None)

    def __set__(self, obj, val):
        setattr(obj, self.private, val)

class User:
    name = Typed()

u = User()
u.name = "Alice"
print(u.name)     # Alice

__delete__ zum Entfernen von Attributen

Definieren Sie __delete__(self, obj), um del obj.attr abzufangen.

class Protected:
    def __set_name__(self, owner, name): self.name = name
    def __get__(self, obj, t):
        return obj.__dict__.get(self.name)
    def __set__(self, obj, v): obj.__dict__[self.name] = v
    def __delete__(self, obj):
        raise AttributeError(f"Cannot delete {self.name}")

class Config:
    host = Protected()

c = Config(); c.host = "localhost"
# del c.host   # AttributeError

Funktionen sind Nicht-Daten-Deskriptoren

Funktionen implementieren __get__, um beim Zugriff über eine Instanz eine gebundene Methode zurückzugeben. So funktioniert die Methodenbindung in Python.

def greet(self):
    return f"Hello from {self}"

class C: pass
C.greet = greet

c = C()
print(c.greet())    # Hello from <C object>

classmethod und staticmethod sind Deskriptoren

classmethod und staticmethod sind integrierte Deskriptor-Klassen, die Funktionen umschließen und den Rückgabewert von __get__ verändern.

class MyClass:
    @classmethod
    def from_string(cls, s):
        return cls()

# classmethod.__get__ returns a bound method with cls
# staticmethod.__get__ returns the plain function

Deskriptor für verzögerte Attribute

Erstellen Sie einen Deskriptor, der einen Wert einmal berechnet und ihn pro Instanz zwischenspeichert.

class LazyAttr:
    def __init__(self, func): self.func = func
    def __set_name__(self, owner, name): self.name = name
    def __get__(self, obj, t):
        if obj is None: return self
        val = self.func(obj)
        obj.__dict__[self.name] = val   # shadows descriptor
        return val

class Report:
    @LazyAttr
    def summary(self):
        print("computing...")
        return "done"

r = Report()
print(r.summary)   # computing... done
print(r.summary)   # done (cached)

property ist ein Deskriptor

property ist selbst ein in C implementierter Daten-Deskriptor. Wenn Sie Deskriptoren verstehen, verstehen Sie auch, wie @property, @classmethod und @staticmethod funktionieren.

class Circle:
    def __init__(self, r): self._r = r

    @property
    def radius(self): return self._r

    @radius.setter
    def radius(self, v):
        if v < 0: raise ValueError
        self._r = v

# property is: property.__get__ = fget, property.__set__ = fset

Reihenfolge der Deskriptorauflösung

Reihenfolge der Attributauflösung in Python: 1) Daten-Deskriptoren aus dem Typ (MRO), 2) das __dict__ der Instanz, 3) Nicht-Daten-Deskriptoren und Klassenvariablen.

# Pseudocode for obj.attr:
# 1. Check type(obj).__mro__ for a data descriptor
# 2. Check obj.__dict__
# 3. Check type(obj).__mro__ for non-data descriptor or class var
# 4. Raise AttributeError

Kurzer Test

Welcher Deskriptor-Typ hat Vorrang vor dem __dict__ der Instanz?

Zusammenfassung

Deskriptoren fangen den Attributzugriff über __get__, __set__ und __delete__ ab. Daten-Deskriptoren haben Vorrang vor dem __dict__ der Instanz, Nicht-Daten-Deskriptoren dagegen nicht. Verwenden Sie __set_name__, um den Attributnamen zu erfahren. property, classmethod und staticmethod sind allesamt Deskriptoren.

Häufig gestellte Fragen

Ist die Lektion „Deskriptoren: __get__, __set__, __delete__“ kostenlos?

Ja — der vollständige Text von „Deskriptoren: __get__, __set__, __delete__“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Python Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Python Academy-Kurs umfasst insgesamt 4 Lektionen.

Was lerne ich in „Deskriptoren: __get__, __set__, __delete__“?

Implementieren Sie das Deskriptorprotokoll zur Steuerung des Attributzugriffs. Du übst Python Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.

Brauche ich Erfahrung, um Python Academy zu starten?

Keine Vorkenntnisse erforderlich. Python Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 3 von 4.

Wie lange dauert die Lektion „Deskriptoren: __get__, __set__, __delete__“?

Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.

Kann ich in dieser Python Academy-Lektion Code schreiben und ausführen?

Ja. Jede Python Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.

Alle Lektionen in diesem Kurs

  1. Wie Python-Klassen erstellt werden
  2. Benutzerdefinierte Metaklassen schreiben
  3. Deskriptoren: __get__, __set__, __delete__
  4. __slots__ und Speicheroptimierung
← Zurück zu Python Academy