Python Academy · leksjon

Deskriptorer: __get__, __set__, __delete__

Implementer deskriptorprotokollen for å styre attributtilgang.

Leksjon 3 av 413 trinn

Deskriptorer: __get__, __set__, __delete__ er en gratis leksjon i Python Academy på CoddyKit. Dette er leksjon 3 av 4. Du kan lese hele leksjonen gratis nedenfor – og deretter øve praktisk i nettleseren med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i Python Academy, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i Python Academy inneholder totalt 4 leksjoner.

Hva er en deskriptor?

En deskriptor er et objekt som definerer __get__, __set__ eller __delete__, og som er tilordnet som et klasse-attributt. Python kaller disse metodene ved attributttilgang.

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

Data- og ikke-datadeskriptorer

Datadeskriptorer definerer __set__ eller __delete__ og har forrang foran instansens __dict__. Ikke-datadeskriptorer, som bare har __get__, viker for __dict__.

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__-signaturen

__get__(self, obj, objtype): obj er instansen, eller None når attributtet hentes fra klassen, mens objtype er klassen.

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__ og validering

Implementer __set__(self, obj, value) for å validere eller transformere en verdi før den lagres.

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 eller nyere kaller __set_name__(owner, name) på deskriptoren når den tilordnes til en klasse, slik at den får tilgang til sitt eget attributtnavn.

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__ for fjerning av attributter

Definer __delete__(self, obj) for å fange opp del obj.attr.

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

Funksjoner er ikke-datadeskriptorer

Funksjoner implementerer __get__ for å returnere en bundet metode når de hentes fra en instans. Det er slik binding av metoder fungerer i 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 og staticmethod er deskriptorer

classmethod og staticmethod er innebygde deskriptorklasser som pakker inn funksjoner og endrer returverdien fra __get__.

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 for late attributter

Bygg en deskriptor som beregner en verdi én gang og mellomlagrer den per instans.

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 er en deskriptor

property er selv en datadeskriptor implementert i C. Når du forstår deskriptorer, blir det enklere å forstå hvordan @property, @classmethod og @staticmethod fungerer.

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

Rekkefølge for deskriptoroppslag

Rekkefølgen for attributtoppslag i Python er: 1) datadeskriptorer fra typen (MRO), 2) instansens __dict__, 3) ikke-datadeskriptorer og klassevariabler.

# 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

Kort kontroll

Hvilken type deskriptor går foran instansens __dict__?

Oppsummering

Deskriptorer fanger opp attributtilgang via __get__, __set__ og __delete__. Datadeskriptorer overstyrer instansens __dict__, mens ikke-datadeskriptorer ikke gjør det. Bruk __set_name__ for å hente attributtnavnet. property, classmethod og staticmethod er alle deskriptorer.

Gratis å komme i gang

Lær deg Python med en AI-veileder – gratis

Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.

Kurs
76
Leksjoner
320

Ofte stilte spørsmål

Er leksjonen «Deskriptorer: __get__, __set__, __delete__» gratis?

Ja – hele teksten i «Deskriptorer: __get__, __set__, __delete__» er gratis å lese her på nettet. For å øve interaktivt med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt, og for å låse opp resten av Python Academy-kurset, kan du oppgradere til CoddyKit PRO. Kurset i Python Academy inneholder totalt 4 leksjoner.

Hva lærer jeg i «Deskriptorer: __get__, __set__, __delete__»?

Implementer deskriptorprotokollen for å styre attributtilgang. Du øver på Python Academy med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.

Trenger jeg erfaring for å begynne med Python Academy?

Ingen tidligere erfaring er nødvendig. Python Academy på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 3 av 4.

Hvor lang tid tar leksjonen «Deskriptorer: __get__, __set__, __delete__»?

De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.

Kan jeg skrive og kjøre kode i denne Python Academy-leksjonen?

Ja. Alle Python Academy-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.

Alle leksjonene i dette kurset

  1. Hvordan Python-klasser opprettes
  2. Skrive egendefinerte metaklasser
  3. Deskriptorer: __get__, __set__, __delete__
  4. __slots__ og minneoptimalisering
← Tilbake til Python Academy