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

Tegyük fel, hogy egy nagyvállalat piaca fokozatosan nő, és ezért több részlegében egy adott időn keresztül évente egyenletesen növelik a létszámot, vagyis minden évben azonos fővel növekszik a dolgozói állomány. A részlegekben mind az induló létszám, mind pedig az éves növekedés eltérő. A kérdés, hogy a növekedési időszak alatt a részlegben együttesen évente hogyan alakul a létszám? Erre kellene egy programmal választ adni.

A helyzetet matematikailag egyszerű modellezni, mert az egyes részlegek állománynövekedése egy adott kezdőértékkel és növekménnyel rendelkező számtani sorozat. A feladat megoldását azon számtani sorozat előállítása jelenti, amely az egyes részsorozatok elemenkénti összegzéséből adódik.

A megoldást eredményező programot több módon is meg lehet alkotni. Pl. listákkal, listaépítő kifejezéssel. Mivel azonban a sorozatok elemei, azaz a létszámok egész számok, ezért szóba jöhet a listánál memóriatakarékosabb range objektum, amely bár konténerobjektumnak számít, de nem tárolja az általa képviselt egész számokat.

Milyen egyszerű lenne a megoldás, ha a range elemenkénti összeadásra lenne képes, mondjuk a + operátorral. De ez nem értelmezett rá. Nem baj, akkor készítünk magunknak egy olyan specializált Range osztályt, amelynek példányai már lehetnek operandusai a + operátornak. De ha már készítünk egy ilyen osztályt, akkor tegyük képessé a kivonás műveletére is. Ekkor egy olyan új Range objektum jön létre, amelynek elemei a kivonás műveletében szereplő Range példányok elemeinek különbsége. Az sem lenne haszontalan, ha egész számmal való szorzást is lehetne végezni, aminek eredménye egy olyan új, Range típusú számtani sorozat lenne, amelynek elemei az eredeti sorozat elemeinek és az egész számnak a szorzata. Az egész számmal való osztás ebben az esetben nem valósítható meg, mert az osztás eredménye általában nem egész szám, így az eredménysorozat már nem lehetne Range típusú.

Az egyéni Range típus megvalósítására egy kézenfekvő megoldás, ha a range beépített típusból mint alaposztályból örököl, és a kívánt új metódusokat kell már csak implementálni. A gond az, hogy ez a módszer nem fog menni, mert a range azon osztályok közé tartozik, amelyekből nem lehet örökölni. A Pythonban van még néhány ilyen osztály, de szerencsére nem sok. Mit lehet akkor tenni?

Ha nem lehet örökölni, akkor megalkotjuk a Range osztályt kompozícióval. Vagyis a példányosításnál a start, stop és step argumentumok alapján előállítunk egy belső használatú range objektumot, és ezt fogjuk használni mindenütt, ahol lehet.

A kompozícióval való osztálydefiniálás egy kicsit több munkával jár, mint ha örökléssel valósítanánk meg, mert a range össze releváns metódusát implementálni kell, még akkor is, ha az csupán egy, a belső range objektumra történő delegáló metódushívást jelenti.

Valósítsuk meg tehát az egyéni Range osztályt. Ennek definícióját, valamint a tesztsorokat és eredményeket láthatjuk alább. A kódok egyszerűek és kommentek nélkül is érthetők, így nem kell magyarázatot fűzni hozzá.

Ebben a bejegyzésben most csak azokat a metódusokat implementáltuk, amelyek olyan Range osztályt valósítanak meg, amely funkcionálisan a range beépített típus képességeivel rendelkezik.

A következő bejegyzésben fogunk továbblépni, és megvalósítani azon metódusokat, amelyek lehetővé teszik, hogy a Range példányok a +, – és * operátorokkal is használhatók legyenek.

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, valamint a „Kompozíció, delegálás és öröklés” 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.