Deskriptorit: __get__, __set__, __delete__
Toteuttakaa deskriptoriprotokolla attribuuttien käytön hallintaan.
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 ... 42Data- 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 # AttributeErrorFunktiot 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 functionLaiska 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__ = fsetDeskriptorien 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 AttributeErrorPikatarkistus
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.
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
- Miten Python-luokat luodaan
- Mukautettujen metaluokkien kirjoittaminen
- Deskriptorit: __get__, __set__, __delete__
- __slots__ ja muistin optimointi