Deskriptorer: __get__, __set__, __delete__
Implementera deskriptorprotokollet för att styra attributåtkomst.
Deskriptorer: __get__, __set__, __delete__ är en gratis lektion i Python Academy på CoddyKit. Detta är lektion 3 av 4. Ni kan läsa hela lektionen gratis nedan och sedan öva praktiskt i webbläsaren med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt. Den ingår i lärvägen för Python Academy, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Python Academy innehåller totalt 4 lektioner.
Vad är en deskriptor
En deskriptor är ett objekt som definierar __get__, __set__ eller __delete__ och tilldelas som ett attribut på en klass. Python anropar dessa metoder när attributet används.
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- och icke-datadeskriptorer
Datadeskriptorer definierar __set__ eller __delete__ och har företräde framför instansens __dict__. Icke-datadeskriptorer, som endast har __get__, lämnar företrädet till __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) # dataSignaturen för __get__
__get__(self, obj, objtype): obj är instansen, eller None när attributet används via klassen, och objtype är 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__ och validering
Implementera __set__(self, obj, value) för att validera eller omvandla ett värde innan det lagras.
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__
Från och med Python 3.6 anropar Python __set_name__(owner, name) på deskriptorn när den tilldelas en klass, vilket ger den tillgång till sitt eget attributnamn.
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__ för att ta bort attribut
Definiera __delete__(self, obj) för att fånga upp 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 # AttributeErrorFunktioner är icke-datadeskriptorer
Funktioner implementerar __get__ för att returnera en bunden metod när de används via en instans. Det är så Pythons metodbindning fungerar.
def greet(self):
return f"Hello from {self}"
class C: pass
C.greet = greet
c = C()
print(c.greet()) # Hello from <C object>classmethod och staticmethod är deskriptorer
classmethod och staticmethod är inbyggda deskriptorklasser som omsluter funktioner och ändrar returvärdet från __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 för lata attribut
Skapa en deskriptor som beräknar ett värde en gång och cachar det 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 är en deskriptor
property är själv en datadeskriptor som implementeras i C. När du förstår deskriptorer blir det lättare att förstå hur @property, @classmethod och @staticmethod fungerar.
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__ = fsetAttributuppslagningens ordning
Ordningen för attributuppslagning i Python: 1) datadeskriptorer från typen (MRO), 2) instansens __dict__, 3) icke-datadeskriptorer och klassvariabler.
# 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 AttributeErrorSnabbkontroll
Vilken typ av deskriptor har företräde framför instansens __dict__?
Sammanfattning
Deskriptorer fångar upp åtkomst till attribut via __get__, __set__ och __delete__. Datadeskriptorer döljer instansens __dict__, medan icke-datadeskriptorer inte gör det. Använd __set_name__ för att ta reda på attributnamnet. property, classmethod och staticmethod är alla deskriptorer.
Lär dig Python med en AI-lärare – gratis
Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.
- Kurser
- 76
- Lektioner
- 320
Vanliga frågor
Är lektionen ”Deskriptorer: __get__, __set__, __delete__” gratis?
Ja – hela texten till ”Deskriptorer: __get__, __set__, __delete__” kan läsas gratis här på webben. Om Ni vill öva interaktivt med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt och låsa upp resten av kursen i Python Academy, kan Ni uppgradera till CoddyKit PRO. Kursen i Python Academy innehåller totalt 4 lektioner.
Vad lär jag mig i ”Deskriptorer: __get__, __set__, __delete__”?
Implementera deskriptorprotokollet för att styra attributåtkomst. Ni övar på Python Academy med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.
Behöver jag någon erfarenhet för att börja lära mig Python Academy?
Du behöver inga förkunskaper. Utbildningen i Python Academy på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 3 av 4.
Hur lång tid tar lektionen ”Deskriptorer: __get__, __set__, __delete__”?
De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.
Kan jag skriva och köra kod i den här Python Academy-lektionen?
Ja. Varje Python Academy-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.
Alla lektioner i den här kursen
- Hur Python-klasser skapas
- Skriva egna metaklasser
- Deskriptorer: __get__, __set__, __delete__
- __slots__ och minnesoptimering