Deskriptorer: __get__, __set__, __delete__
Implementer deskriptorprotokollen for å styre attributtilgang.
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 ... 42Data- 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 # AttributeErrorFunksjoner 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 functionDeskriptor 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__ = fsetRekkefø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 AttributeErrorKort 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.
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
- Hvordan Python-klasser opprettes
- Skrive egendefinerte metaklasser
- Deskriptorer: __get__, __set__, __delete__
- __slots__ og minneoptimalisering