Python Academy · Lektion

Deskriptorer: __get__, __set__, __delete__

Implementera deskriptorprotokollet för att styra attributåtkomst.

Lektion 3 av 413 steg

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 ... 42

Data- 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)   # data

Signaturen 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   # AttributeError

Funktioner ä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 function

Deskriptor 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__ = fset

Attributuppslagningens 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 AttributeError

Snabbkontroll

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.

Gratis att börja

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

  1. Hur Python-klasser skapas
  2. Skriva egna metaklasser
  3. Deskriptorer: __get__, __set__, __delete__
  4. __slots__ och minnesoptimering
← Tillbaka till Python Academy