ProgrammatieSenior Python ontwikkelaar

Wat zijn descriptors in Python? Hoe worden ze geïmplementeerd, waarvoor worden ze gebruikt, wat is het verschil met property en wat zijn typische fouten bij het gebruik ervan?

Slaag voor sollicitatiegesprekken met de Hintsage AI-assistent

Antwoord

Een descriptor is een object dat een van de methoden get, set en delete implementeert. Het stelt je in staat de toegang tot de attributen van een klasse te controleren.

Standaardmethoden van de descriptor:

  • __get__(self, instance, owner)
  • __set__(self, instance, value)
  • __delete__(self, instance)

Descriptors zijn:

  • Klassiek (data descriptors) — implementeren set, hebben prioriteit boven gewone attributen;
  • Niet-klassiek (non-data descriptors) — implementeren alleen get, hebben een lagere prioriteit dan gewone attributen.

Voorbeeld van gebruik:

class OnlyPositive: def __init__(self): self._name = '_value' def __get__(self, instance, owner): return instance.__dict__[self._name] def __set__(self, instance, value): if value < 0: raise ValueError('Waarde moet >= 0 zijn') instance.__dict__[self._name] = value class Account: value = OnlyPositive() def __init__(self, value): self.value = value acc = Account(10) acc.value = -1 # ValueError!

property is slechts syntactische suiker voor het maken van descriptors op klasseniveau.

Misleidende Vraag

Wat gebeurt er als je een descriptor als een attribuut van een instantie maakt, en niet van de klasse?

Velen denken dat de descriptor zal werken, maar dat is niet het geval.

Correct antwoord:

Een descriptor werkt alleen als deze rechtstreeks als een attribuut van de klasse is gedefinieerd. Als de descriptor als een attribuut van een instantie wordt ingesteld, worden de methoden get/set niet aangeroepen — de gebruikelijke logica voor het toegang krijgen tot een attribuut.

Voorbeelden van echte fouten door gebrek aan kennis over de nuances van het onderwerp


Verhaal

Het gebruik van property in plaats van een volledige descriptor

Voor validatie en andere gerelateerde attributen gebruikte de ontwikkelaar een eenvoudige property, wat leidde tot frequente duplicatie van logica en de onmogelijkheid om code tussen verschillende klassen te hergebruiken.


Verhaal

Het niet naleven van immutabiliteit bij hergebruik van opslag

De descriptor bewaarde gegevens in een intern attribuut van zijn eigen klasse (self.x), en niet in de interne opslag van de instantie, waardoor het attribuut "gemeenschappelijk" werd en verschillende instanties van de klasse elkaars waarden overschreven — gegevens "lekten" tussen objecten.


Verhaal

Data descriptor en non-data descriptor verwisseld

In een complexe hiërarchie werd de implementatie van set overgeslagen, waardoor een gewoon attribuut van een instantie de descriptor overschreef, wat het hele validatiemechanisme brak — de bug manifesteerde zich niet altijd, en het was moeilijk om te debuggen.