Python Academy · Oppitunti

Deskriptorit: __get__, __set__, __delete__

Toteuttakaa deskriptoriprotokolla attribuuttien käytön hallintaan.

Oppitunti 3/413 vaihetta

Deskriptorit: __get__, __set__, __delete__ on ilmainen Python Academy-oppitunti CoddyKitissä. Tämä on oppitunti 3/4. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu Python Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Python Academy-kurssilla on yhteensä 4 oppituntia.

Mikä on deskriptori?

Deskriptori on olio, joka määrittelee metodin __get__, __set__ tai __delete__ ja joka on määritetty luokan attribuutiksi. Python kutsuu näitä metodeja attribuutin käytön yhteydessä.

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- ja non-data-deskriptorit

Data-deskriptorit määrittelevät metodin __set__ tai __delete__, ja ne ohittavat ilmentymän __dict__-sanakirjan. Non-data-deskriptorit (joilla on vain __get__) väistyvät __dict__-sanakirjan tieltä.

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

__get__(self, obj, objtype): obj on ilmentymä (tai None, kun attribuuttia käytetään luokan kautta), ja objtype on luokka.

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__ ja validointi

Toteuta __set__(self, obj, value), jos haluat validoida tai muuntaa arvon ennen sen tallentamista.

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 ja uudemmat kutsuvat kuvaajan __set_name__(owner, name)-metodia, kun kuvaaja määritetään luokkaan. Näin se saa käyttöönsä oman attribuuttinsa nimen.

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__ attribuutin poistamista varten

Määritä __delete__(self, obj), jos haluat siepata toiminnon 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

Funktiot ovat non-data-deskriptoreita

Funktiot toteuttavat __get__-metodin, joka palauttaa sidotun metodin, kun funktiota käytetään ilmentymässä. Näin Python sitoo metodit.

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

class C: pass
C.greet = greet

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

classmethod ja staticmethod ovat deskriptoreita

classmethod ja staticmethod ovat sisäänrakennettuja deskriptoriluokkia, jotka käärivät funktioita ja muuttavat __get__-metodin palauttamaa arvoa.

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

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

Laiska attribuuttideskriptori

Rakenna deskriptori, joka laskee arvon kerran ja tallentaa sen välimuistiin ilmentymäkohtaisesti.

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 on deskriptori

property on itsessään C-kielellä toteutettu data-deskriptori. Deskriptorien ymmärtäminen auttaa ymmärtämään, miten @property, @classmethod ja @staticmethod toimivat.

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

Deskriptorien hakujärjestys

Pythonin attribuuttien hakujärjestys: 1) tyypin (MRO) data-deskriptorit, 2) instanssin __dict__, 3) ei-data-deskriptorit ja luokkamuuttujat.

# 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

Pikatarkistus

Minkä tyyppinen deskriptori ohittaa instanssin __dict__:n?

Kertaus

Deskriptorit sieppaavat attribuuttien käytön metodien __get__, __set__ ja __delete__ avulla. Data-deskriptorit peittävät instanssin __dict__:n, ei-data-deskriptorit eivät. Käyttäkää __set_name__-metodia attribuutin nimen selvittämiseen. property, classmethod ja staticmethod ovat kaikki deskriptoreita.

Aloita maksutta

Opi Python tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
76
Oppitunnit
320

Usein kysytyt kysymykset

Onko oppitunti ”Deskriptorit: __get__, __set__, __delete__” ilmainen?

Kyllä – oppitunnin ”Deskriptorit: __get__, __set__, __delete__” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko Python Academy-kurssin, päivitä CoddyKit PROhon. Python Academy-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”Deskriptorit: __get__, __set__, __delete__”?

Toteuttakaa deskriptoriprotokolla attribuuttien käytön hallintaan. Harjoittelet Python Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni Python Academy-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin Python Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 3/4.

Kuinka kauan ”Deskriptorit: __get__, __set__, __delete__”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä Python Academy-oppitunnilla?

Kyllä. Jokainen Python Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. Miten Python-luokat luodaan
  2. Mukautettujen metaluokkien kirjoittaminen
  3. Deskriptorit: __get__, __set__, __delete__
  4. __slots__ ja muistin optimointi
← Takaisin: Python Academy