Egyéni Range típus definiálása összeadás, kivonás és szorzás műveleti képességekkel – 2. rész

Az előző bejegyzésben egy feladat kapcsán olyan specializált Range osztály definiálását kezdtük el, amely példányai a beépített range típushoz hasonlóak, de a cél, hogy a következő képességekkel is rendelkezzenek:

1) két azonos elemszámú Range, vagy azonos elemszámú Range és range objektum összeadható a + operátorral, vagy egymásból kivonható a – operátorral. Az eredményül kapott új Range objektum elemei a két sorozat azonos indexű elemeinek összege, illetve különbsége.

2) egy Range objektumhoz egy egész szám adható a ’+’ operátorral, illetve vonható ki a ’–’ operátorral. Az eredményül kapott új Range objektum elemei az eredeti Range elemei növelve, illetve csökkentve az adott egésszel.

3) egy Range objektum megszorozható egy egész számmal a ’*’ operátorral. Az eredményül kapott új Range objektum elemei az eredeti Range elemei szorozva az adott egésszel.

4) Egy Range példány + vagy – előjellel látható el. Az előbbi esetben önmagát kapjuk vissza, az utóbbi esetben egy olyan új Range objektumot, amelynek elemei az eredeti Range példány elemeinek -1-szerese.

Legutóbb addig jutottunk, hogy definiáltuk a Range osztályban a sorozat típusú konténerekre jellemző __repr__, __len__, __contains__, __getitem__, __bool__, count() és index() metódusokat. A fent felsorolt képességeket most fogjuk megvalósítani az osztályban.

Ahhoz, hogy a Range által képviselt véges, egész számokat tartalmazó számtani sorozatok elemenkénti összeadásából, illetve egy egész számmal történő elemenkénti szorzással előálló sorozatok start, step és stop argumentumait helyesen tudjuk meghatározni, nem árt egy előzetes matematikai átgondolás. Ezt foglalja össze a következő ábra:

Láthatjuk, hogy az összeadás vagy egésszel való szorzás eredményeként kapott sorozatoknak a start és step értékét könnyű megkapni, viszont a stop érték meghatározásához kell némi megfontolás.

Ha ezt átgondoltuk és megértettük, akkor a ’+’ operátornak megfelelő __add__ metódus, valamint a ’*’ operátornak megfelelő __mul__ metódus implementálása nem nehéz. Ezt láthatjuk az alábbi kódsorokban. Mivel az összeadás és szorzás kommutatív művelet, ezért a fordított kiértékelést végző __radd__ és __rmul__ metódusokat is implementáltuk.

Az összeadás és az egész számmal való szorzás rendelkezésre állásával a kivonás ’–’ operátorához tartozó __sub__ valamint a negálást végző __neg__ metódust is viszonylag egyszerűen megvalósíthatjuk:

A fenti kódban a teljesség kedvéért az egyenlőségvizsgálathoz szükséges __eq__ metódust is láthatjuk, valamint, hogy a Range példány halmaz eleme, illetve szótár kulcsa is lehessen, implementáltuk a __hash__ metódust is.

Mindezek után a Range osztály teljes definíciója a következő:

Annak bemutatására, hogy az így kialakított Range osztály teljesíti a fent sorolt elvárásokat, néhány tesztfuttatást látunk alább. /Az itt szereplő segédfüggvény az eredmények ellenőrzését segítő áttekinthető megjelenítést szolgálja/

E bejegyzés témájához a Python tudásépítés lépésről lépésre című e-könyv következő részei kapcsolódnak: a „Beépített konténerobjektumok” fejezet „range” alfejezete, az „Osztály vigyázz! – típuslétrehozás osztályokkal” fejezet, a „Mágikus metódusok egyedi igényre szabott osztályokban” fejezet, a „Kompozíció, delegálás és öröklés” fejezet, valamint „Osztályok operandus szerepben” fejezet.

Érdekel a Python tudásépítés lépésről lépésre az alapoktól az első asztali alkalmazásig című e-könyv.