ProgrammatieBackend ontwikkelaar

Leg het 'Sequence' protocol in Python uit, hoe je het implementeert en wat het verschil is met gewoon iterable objecten?

Slaag voor sollicitatiegesprekken met de Hintsage AI-assistent

Antwoord.

In Python definieert het 'Sequence' protocol een interface voor objecten die indexeerbaar en iteratief zijn, zoals lijsten of tuples. Historisch gezien zijn sequenties ontstaan vanaf de eerste versies van Python om natuurlijke bewerkingen op datastructuren te ondersteunen: indexering, slicing, en iteratie over elementen.

Probleem — om een gebruikersklasse zich als sequentie te laten gedragen, zijn alleen de methoden iter en next niet voldoende. Voor volledige ondersteuning van sequentiegedrag zijn extra methoden nodig.

Oplossing — om een eigen sequentietype te implementeren, moet je de methoden getitem (noodzakelijk voor indexering en slicing) en optioneel len (voor len() en om de lengte te controleren) definiëren. Zo zal het object iteratie, toegang via index, slicing en vele standaard Python-operaties met sequenties ondersteunen.

Voorbeeldcode:

class MyCounter: def __init__(self, stop): self._stop = stop def __getitem__(self, index): if 0 <= index < self._stop: return index * 10 else: raise IndexError('Out of range') def __len__(self): return self._stop c = MyCounter(5) print(c[3]) # 30 print(len(c)) # 5 for x in c: print(x)

Belangrijkste kenmerken:

  • Het object ondersteunt indextoegang en slicing via getitem.
  • Voor ondersteuning van de len() functie is len nodig.
  • Iteratie is gebaseerd op getitem, niet op iter, als iter niet is gedefinieerd.

Vragen met een valstrik.

Als ik alleen iter en next implementeer, wordt mijn object een Sequence?

Nee. Een dergelijk object zal alleen iterabel zijn (iterable), maar niet een sequentie. Het zal geen indexering, slicing, of standaard functies van lijstachtige objecten ondersteunen.

Is het verplicht om getitem te implementeren voor ondersteuning van de for-lus?

Niet verplicht. Als iter is geïmplementeerd, zal for werken. Maar als er geen iter is, zal de interpreter proberen getitem te gebruiken, te beginnen bij index 0, totdat er een IndexError optreedt. Daarom is voor een sequence voldoende dat getitem is geïmplementeerd.

Kan ik getitem alleen voor int implementeren en niet voor slice?

Technisch gezien zal het object werken voor c[0], maar een poging om een slice c[1:4] te nemen zal falen. Om slicing te ondersteunen, moet getitem in staat zijn om slice-objecten te verwerken (zie slice.indices en isinstance(key, slice)).

Voorbeeldcode:

class S: def __getitem__(self, idx): if isinstance(idx, slice): return [x for x in range(idx.start or 0, idx.stop or 10, idx.step or 1)] return idx * 2

Typische fouten en anti-patronen

  • Definiëren alleen iter, in de veronderstelling dat het object een volledige sequentie wordt.
  • Implementeren getitem, maar verwerken geen slice-objecten.
  • Implementeren geen len, waardoor len(obj) een TypeError oproept.

Voorbeeld uit de praktijk

Negatieve case

Een aangepaste structuur geïmplementeerd, alleen iter gedefinieerd, denkend dat nu slicing en indexering mogelijk zijn.

Voordelen:

  • Werkt in een for-lus en ondersteunt generators.

Nadelen:

  • Geen ondersteuning voor de syntaxis obj[5] of obj[1:3], het faalt met een fout.
  • len(obj) werkt ook niet.

Positieve case

Een klasse implementeert getitem met ondersteuning voor slicing en int-indexen, evenals len.

Voordelen:

  • Ondersteunt alle sequentie-operaties: slicing, indexering, len, iteratie.
  • Integratie met de standaardbibliotheek (bijvoorbeeld, random.choice).

Nadelen:

  • Moet zorgvuldig de verwerking van slices implementeren, anders kunnen er bugs optreden bij het werken met slices.