Az, hogy float típusú számok egyenlőségvizsgálatánál körültekintően kell eljárni általában ismert. A véges számú biten történő ábrázolás miatt ugyanis a számítási műveletek eredménye nem biztos, hogy meg fog egyezni a matematikailag várható egzakt értékkel. Például elvben a 0.1+0.2 == 0.3 kifejezés igaz (True) értékű kellene, hogy legyen, de lefuttatva mégis hamis (False) értéket kapunk. Éppen ezért, ha olyan két szám egyenlőségét vizsgáljuk, amelyek közül legalább az egyik float típusú, akkor az egyenlőséget csak adott – az alkalmazásunk számítási pontosságának igényéhez igazodó – hibahatáron belül tudjuk értelmezni. Hasonló a helyzet olyan komplex számok egyenlőségvizsgálatánál, amelyek valós vagy képzetes része float típusú.
Ilyen esetekben a tényeles egyenlőséget ellenőrző == operátor helyett általában a szabványos könyvtár math moduljában rendelkezésre álló isclose() függvénnyel végezzük az értékek összehasonlítását. Ha komplex számok is szóba jöhetnek, akkor a cmath modul isclose() függvényét lehet alkalmazni.
A float típusú számok egyenlőségének problematikája nem csak két szám explicit összevetésénél merül fel, hanem implicit módon konténerobjektumok értékkeresésen alapuló metódusainál is. Ilyen például az in operátor alkalmazásakor meghívott __contains__ metódus, valamint változtatható konténereknél a remove(). Ezeken felül sorozattípusú konténereknél (list, tuple, deque, array) ilyen a count() és az index() metódus is. Ezek mindegyikénél azt tapasztaljuk, hogy ha van a sorozatban 0.3 értékű elem, akkor ha a metódusnak argumentumként a 0.1+0.2 számított értéket adjuk át, hibás eredményt kapunk, mert a metódusokon belül egzakt egyenlőségvizsgálat történik.
Ezt két módon tudjuk kiküszübölni:
- a metódushívások előtt az argumentumokat megfelelően előkészítjük. Pl. kerekítéssel: round(0.1+0.2, 9).
- saját készítésű konténerosztályokat hozunk létre, amelyekben az értékkeresésen alapuló metódusokat úgy írjuk felül, hogy azok float értékkel vagy float komponensű komplex számokkal meghívva helyes eredményt adjanak.
A két lehetőség közül választási szempont lehet a futási idő. Ugyanis a saját készítésű osztályokban felülírt metódusok lassabban fognak futni, mint ha azokat a beépített típusokon közvetlenül hívnánk meg. Éppen ezért, ha nagyméretű adathalmazzal kell dolgozni és a futási idő szempont, akkor inkább az argumentumok előkészítése a jobb megközelítés. Egyéb esetben a metódusok felülírása, mert azt csak egyszer kell elvégezni és utána az egyéni típus ugyanúgy és ugyanott használható, mint a beépített, és az argumentumként átadandó keresett értékekkel nem kell előzetesen külön foglalkozni.
A továbbiakban a második megoldás ismertetjük, már csak azért is, mert alkalmat teremt számos Python nyelvi konstukció mélyebb megértésére vagy gyakorlására. Sorozattípusú konténerek (list, tuple, deque, array) egyéni változatát fogjuk elkészíteni, mert ezekkel mindegyik, értékkeresésen alapuló metódus felülírása bemutatható.
Az egyéni típusok elkészítésének két mozzanata van:
- alosztály létrehozása a beépített típus alapján
- metódusok felülírása
Vegyük elsőként a list beépített típust. Legyen a saját osztályunk neve List. Ezt mint alosztályt örökléssel egyszerűen létre tudjuk hozni, és ebben az értékkeresésen alapuló metódusokat egyszerűen felülírjuk. Ezt láthajuk az alábbi kódban.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
import sys from typing import Any import cmath class List(list): @staticmethod def _are_equal(x: Any, y: Any) -> bool: """Az argumentumok egzakt egyenlőségét vizsgálja, kivéve, ha az argumentumok számok és ezek bármelyike float típusú vagy olyan komplex szám, amelynek valós vagy képzetes része float típusú. Ekkor az egyenlőséget adott hibahatáron belül értelmezi. """ if (isinstance(x, (int, float, complex)) and isinstance(y, (int, float, complex)) and any(isinstance(z, float) for z in (x.real, x.imag, y.real, y.imag))): return cmath.isclose(x, y) return x == y def __contains__(self, value: Any) -> bool: """True értékkel tér vissza, ha a megadott érték szerepel az elemek között.""" return any(self._are_equal(v, value) for v in self) def count(self, value: Any) -> int: """Azzal az egész számmal tér vissza, ahányszor a megadott érték a sorozatban előfordul.""" return sum(1 for v in self if self._are_equal(v, value)) def index(self, value: Any, start: int = 0, stop: int = sys.maxsize) -> int: """Visszaadja a megadott érték első előfordulásának indexét. Ha az érték nem található a sorozatban ValueError kivételt dob. A keresés alapértelmezetten a teljes sorozatban történik, de a start és stop argumentumokkal meg lehet határozni azon részsorozat kezdő és végindexét, ahol a keresés történjen. """ for i in range(start, min(stop, len(self))): if self._are_equal(self[i], value): return i raise ValueError(f'{value} nincs a sorozatban.') def remove(self, value: Any) -> None: """Eltávolítja a megadott értéket, amennyiben az szerepel az elemek között. Ha nem, akkor ValueError kivételt dob.""" for i in range(len(self)): if self._are_equal(self[i], value): del self[i] return raise ValueError(f'{value} nincs a sorozatban.') |
A felülírt metódusokban a helyes eredményt az _are_equal() metódus biztosítja. Ez az egyenlőség megállapításához a == operátort használja kivéve, ha az argumentumok számok és bármelyik float típusú vagy olyan komplex szám, amelynek valós vagy képzetes része float típusú. Ekkor az egyenlőséget adott hibahatáron belül értelmezi a cmath modul isclose() függvényének segítségével. Azért nem a math modul isclose() függvényét használjuk, mert a sorozatelemek komplex számok is lehetnek, és kihasználtuk, hogy a cmath. isclose() mind float, mind complex típusú számokat tud fogadni. A feltételellenőrzésnél pedig azt használtuk ki, hogy minden számtípus rendelkezik a valós és képzetes részeket visszaadó real és imag attribútumokkal. (Valós számok esetében az imag természetesen zérus értékű.)
Ha hasonló módon készítjük el a többi sorozattípusú konténer alosztályát, akkor hamar rájövünk, hogy a metódusok felülírása mindegyikben ugyanaz, mint a List esetében. Kivételt képez a tuple-ból örökölt Tuple, amelyben a remove() nem értelmezett, minthogy a tuple (és így a Tuple) konténer változtathatatlan objektum. Ezért tehát a remove() metódust nem kell felülírni.
Ha programíráskor forráskódmásolás merül fel, akkor mindig érdemes átgondolni, hogy lehet-e úgy átalakítani (refaktorálni) a kódot, hogy kiküszöböljük a másolást. Ugyanis ez egy esetleges módosításakor potenciális hibaforrás lehet, például ha nem minden másolt kódrészben történik meg a változtatás.
Jelen esetben a metódusdefiníciókat ki tudjuk szervezni két mixin osztályba. Az egyikbe, amelynek neve legyen ImmutableLookupMixin, azokat a metódusokat szerepeltetjük, amelyek változtathatatlan objektumokon is érvényesek, vagyis a __contains__, count() és index() metódusokat. És ide helyezzük az _are_equal() metódust is. A másik, MutableLookupMixin nevű mixin osztály pedig örökli az ImmutableLookupMixin osztályt, és tartalmazza a remove() definícióját. A MutableLookupMixin osztály tehát a változtatható példányokat eredményező típusokhoz használható. Ezek, valamint a megfelelő beépített típusok öröklésével a List, Tuple, Deque és Array egyéni osztályok egyszerűen létrehozhatók. Mindez alább látható.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
import sys from array import array from collections import deque from typing import Any from math import isclose class ImmutableLookupMixin: @staticmethod def _are_equal(x: Any, y: Any) -> bool: if (isinstance(x, (int, float, complex)) and isinstance(y, (int, float, complex)) and any(isinstance(z, float) for z in (x.real, x.imag, y.real, y.imag))): return isclose(x, y) return x == y def __contains__(self, value: Any) -> bool: return any(self._are_equal(v, value) for v in self) def count(self, value: Any) -> int: return sum(1 for v in self if self._are_equal(v, value)) def index(self, value: Any, start: int = 0, stop: int = sys.maxsize) -> int: for i in range(start, min(stop, len(self))): if self._are_equal(self[i], value): return i raise ValueError(f'{value} is not in the sequence.') class MutableLookupMixin(ImmutableLookupMixin): def remove(self, value: Any) -> None: for i in range(len(self)): if self._are_equal(self[i], value): del self[i] return raise ValueError(f'{value} is not in the sequence.') class List(MutableLookupMixin, list): ... class Tuple(ImmutableLookupMixin, tuple): ... class Deque(MutableLookupMixin, deque): ... class Array(MutableLookupMixin, array): ... |
Ennek a megoldásnak azonban van egy hátránya, mégpedig az, hogy az isclose() függvénynek az alapértelmezettől eltérő tolerancia értékeket nem lehet meghatározni. Ezt az __init__ metódusban lehetne megadni például rel_tol és abs_tol nevű attribútumok létrehozásával. Azonban az ImmutableLookupMixin osztályban nem lehet definiálni az __init__ metódust, mert változtathatatlan objektumokhoz nem tudunk ilyen módon utólag adatattribútumot rendelni.
Lehetne a __new__ metódus felülírásával célt érni, de erre nincs szükség, ha nem ragaszkodunk a mixin osztályokkal történő megoldáshoz. E helyett egy osztálydekorátort készítünk, amely paraméterezhető a relatív és abszolút eltérés kívánt értékével. Ezt a dekorátort és használatát mutatjuk alább. Az osztályok dekorálását mind a @ szintaxissal, mind függvényhívással láthatjuk. Ez utóbbit normál módon (class kulcsszóval) és dinamikus módon (type() függvénnyel) definiált osztályokra is alkalmaztuk.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
import sys from array import array from collections import deque from typing import Any from cmath import isclose def override_lookups(cls=None, *, rel_tol=1e-9, abs_tol=0): """Dekorátorfüggvény, amely egy sorozattípusú konténer értékkeresésen alapuló metódusait (__contains__, count(), index(), remove()) írja felül annak érdekében, hogy ha a keresett érték float típusú szám, vagy olyan komplex szám, amelynek valós vagy képzetes része float típusú, akkor az egyenlőséget adott hibahatáron belül értelmezi. Egyenlőnek tekinti, ha az értékek eltérésének abszolútértékére a megadott relatív és abszolút hiba közül az egyik teljesül. """ def _decorator(cls): def _are_equal(x: Any, y: Any) -> bool: if (isinstance(x, (int, float, complex)) and isinstance(y, (int, float, complex)) and any(isinstance(z, float) for z in (x.real, x.imag, y.real, y.imag))): return isclose(x, y, rel_tol=rel_tol, abs_tol=abs_tol) return x == y _are_equal = staticmethod(_are_equal) def __contains__(self, value: Any) -> bool: return any(self._are_equal(v, value) for v in self) def count(self, value: Any) -> int: return sum(1 for v in self if self._are_equal(v, value)) def index(self, value: Any, start: int = 0, stop: int = sys.maxsize) -> int: for i in range(start, min(stop, len(self))): if self._are_equal(self[i], value): return i raise ValueError(f'{value} nincs a sorozatban.') def remove(self, value: Any) -> None: for i in range(len(self)): if self._are_equal(self[i], value): del self[i] return raise ValueError(f'{value} nincs a sorozatban.') # Metódusok felülírás az osztályobjektumon új metódus-attribútumok hozzárendelésével. # Csak meglévő metódushoz rendelünk újat, mert nem változtatható objektumoknál a remove() nem értelmezett. for func in (_are_equal, __contains__, count, index): setattr(cls, func.__name__, func) if hasattr(cls, 'remove'): setattr(cls, 'remove', remove) return cls if cls is None: return _decorator return _decorator(cls) @override_lookups class List(list): ... @override_lookups(rel_tol=1e-12) class ScientificList(list): ... @override_lookups class Tuple(tuple): ... class Deque(deque): ... Deque = override_lookups(Deque) Array = override_lookups(type('Array', (array,), {}), rel_tol=1e-10) |
A List, Tuple, Deque és Array osztályok elvárt működésének ellenőrzéséhez minden metódushoz készítünk egy tesztelő függvényt:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
def test_contains_method(sequence, test_args: list[str], expected_results: tuple): if isinstance(sequence, (List, Tuple)): print(f'\nTesztelt sorozat: {type(sequence).__name__}({list(sequence)})') else: print(f'\nTesztelt sorozat: {sequence}') failures = {} for arg, result in zip(test_args, expected_results): try: assert (eval(arg) in sequence) == result except AssertionError: failures[f'__contains__({arg})'] = eval(arg) in sequence if failures: print('Hibák a __contains__() metódus ("in" operátor) eredményében:') for key, value in failures.items(): print('\t{} = {}'.format(key, value)) else: print('Nincs hiba a __contains__() metódus eredményében.') def test_count_method(sequence, test_args: list[str], expected_results: tuple): if isinstance(sequence, (List, Tuple)): print(f'\nTesztelt sorozat: {type(sequence).__name__}({list(sequence)})') else: print(f'\nTesztelt sorozat: {sequence}') failures = {} for arg, result in zip(test_args, expected_results): try: assert sequence.count(eval(arg)) == result except AssertionError: failures[f'count({arg})'] = sequence.count(eval(arg)) if failures: print('Hibák a count() metódus eredményében:') for key, value in failures.items(): print('\t{} = {}'.format(key, value)) else: print('Nincs hiba a count() metódus eredményében.') def test_index_method(sequence, test_args: list[str], expected_results: tuple): if isinstance(sequence, (List, Tuple)): print(f'\nTesztelt sorozat: {type(sequence).__name__}({list(sequence)})') else: print(f'\nTesztelt sorozat: {sequence}') failures = {} for arg, result in zip(test_args, expected_results): try: assert sequence.index(eval(arg)) == result except AssertionError: failures[f'index({arg})'] = sequence.index(eval(arg)) except ValueError as ve: if type(ve) is result: pass else: failures[f'index({arg})'] = f'-> ValueError: {arg} nincs a sorozatban.' if failures: print('Hibák az index() metódus eredményében:') for key, value in failures.items(): print('\t{}: {}'.format(key, value)) else: print('Nincs hiba az index() metódus eredményében.') def test_remove_method(sequence, test_args: list[str], expected_results: tuple): if isinstance(sequence, (List, Tuple)): print(f'\nTesztelt sorozat: {type(sequence).__name__}({list(sequence)})') else: print(f'\nTesztelt sorozat: {sequence}') failures = {} for arg, result in zip(test_args, expected_results): try: sequence.remove(eval(arg)) except ValueError as ve: if type(ve) is result: pass else: failures[f'remove({arg})'] = f'-> ValueError: {arg} nincs a sorozatban.' if failures: print('Hibák a remove() metódus végrehajtásakor:') for key, value in failures.items(): print('\t{}: {}'.format(key, value)) else: print('Nincs hiba a remove() metódus végrehajtásakor.') |
A teszteket mind a beépített típusok, mind a saját készítésű osztályok példányaira elvégezzük, hogy össze lehessen vetni az eltérő működést. Ennek érdekében minden osztály példányát azonos sorozatelemekkel hozzuk létre, és a tesztargumentumok sorozata is azonos. Ez utóbbi elemeit karakterláncként adjuk meg, hogy a tesztfüggvényekben egyszerű módon ki tudjuk írni, hogy mely esetekben kapunk helytelen eredményt.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
# TESZTEK végrehajtása. # Sorozatelemek. test_items = (4, 0.3, 4, 0.3, 4, 1 + 0.3j, 1 + 0.3j) # Tesztértékek. test_arguments = ['4', '"4"', '4.0', '0.3', '0.1 + 0.2', 'complex(1, 0.3)', 'complex(1, 0.1 + 0.2)'] # A tesztelt metódusok és az adott sorozatelemek esetén az alkalmazott tesztértékekhez elvárt eredmények. test_methods_expected_results = [(test_contains_method, (True, False, True, True, True, True, True)), (test_count_method, (3, 0, 3, 2, 2, 2, 2)), (test_index_method, (0, ValueError, 0, 1, 1, 5, 5)), (test_remove_method, (None, ValueError, None, None, None, None, None))] for test_method, expected_results in test_methods_expected_results: tested_method_name = m_name if (m_name := test_method.__name__.split('_')[1]) != 'contains' else f'__{m_name}__' print('\n' + '-' * 20, f'{tested_method_name}() metódus teszt', '-' * 20) for Seq in (list, List, tuple, Tuple, deque, Deque, array, Array): if Seq not in (array, Array): # Kizárjuk a remove() metódus tesztelését a változtathatatlan tuple és Tuple konténerekre. if not (test_method.__name__ == 'test_remove_method' and Seq in (tuple, Tuple)): test_method(Seq(test_items), test_arguments, expected_results) else: # Mivel a konténerpéldány előállítása array és Array esetén eltér a többi típusétól, ezért külön kezeljük. test_method(Seq('d', test_items[:-2]), test_arguments[:-2], expected_results[:-2]) |
A tesztek kiírt eredményét metódusonként alább láthatjuk. Ezek visszaigazolják, hogy a List, Tuple, Deque és Array osztályok a vártnak megfelelően működnek.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
-------------------- __contains__() metódus teszt -------------------- Tesztelt sorozat: [4, 0.3, 4, 0.3, 4, (1+0.3j), (1+0.3j)] Hibák a __contains__() metódus ("in" operátor) eredményében: __contains__(0.1 + 0.2) = False __contains__(complex(1, 0.1 + 0.2)) = False Tesztelt sorozat: List([4, 0.3, 4, 0.3, 4, (1+0.3j), (1+0.3j)]) Nincs hiba a __contains__() metódus eredményében. Tesztelt sorozat: (4, 0.3, 4, 0.3, 4, (1+0.3j), (1+0.3j)) Hibák a __contains__() metódus ("in" operátor) eredményében: __contains__(0.1 + 0.2) = False __contains__(complex(1, 0.1 + 0.2)) = False Tesztelt sorozat: Tuple([4, 0.3, 4, 0.3, 4, (1+0.3j), (1+0.3j)]) Nincs hiba a __contains__() metódus eredményében. Tesztelt sorozat: deque([4, 0.3, 4, 0.3, 4, (1+0.3j), (1+0.3j)]) Hibák a __contains__() metódus ("in" operátor) eredményében: __contains__(0.1 + 0.2) = False __contains__(complex(1, 0.1 + 0.2)) = False Tesztelt sorozat: Deque([4, 0.3, 4, 0.3, 4, (1+0.3j), (1+0.3j)]) Nincs hiba a __contains__() metódus eredményében. Tesztelt sorozat: array('d', [4.0, 0.3, 4.0, 0.3, 4.0]) Hibák a __contains__() metódus ("in" operátor) eredményében: __contains__(0.1 + 0.2) = False Tesztelt sorozat: Array('d', [4.0, 0.3, 4.0, 0.3, 4.0]) Nincs hiba a __contains__() metódus eredményében. -------------------- count() metódus teszt -------------------- Tesztelt sorozat: [4, 0.3, 4, 0.3, 4, (1+0.3j), (1+0.3j)] Hibák a count() metódus eredményében: count(0.1 + 0.2) = 0 count(complex(1, 0.1 + 0.2)) = 0 Tesztelt sorozat: List([4, 0.3, 4, 0.3, 4, (1+0.3j), (1+0.3j)]) Nincs hiba a count() metódus eredményében. Tesztelt sorozat: (4, 0.3, 4, 0.3, 4, (1+0.3j), (1+0.3j)) Hibák a count() metódus eredményében: count(0.1 + 0.2) = 0 count(complex(1, 0.1 + 0.2)) = 0 Tesztelt sorozat: Tuple([4, 0.3, 4, 0.3, 4, (1+0.3j), (1+0.3j)]) Nincs hiba a count() metódus eredményében. Tesztelt sorozat: deque([4, 0.3, 4, 0.3, 4, (1+0.3j), (1+0.3j)]) Hibák a count() metódus eredményében: count(0.1 + 0.2) = 0 count(complex(1, 0.1 + 0.2)) = 0 Tesztelt sorozat: Deque([4, 0.3, 4, 0.3, 4, (1+0.3j), (1+0.3j)]) Nincs hiba a count() metódus eredményében. Tesztelt sorozat: array('d', [4.0, 0.3, 4.0, 0.3, 4.0]) Hibák a count() metódus eredményében: count(0.1 + 0.2) = 0 Tesztelt sorozat: Array('d', [4.0, 0.3, 4.0, 0.3, 4.0]) Nincs hiba a count() metódus eredményében. -------------------- index() metódus teszt -------------------- Tesztelt sorozat: [4, 0.3, 4, 0.3, 4, (1+0.3j), (1+0.3j)] Hibák az index() metódus eredményében: index(0.1 + 0.2): -> ValueError: 0.1 + 0.2 nincs a sorozatban. index(complex(1, 0.1 + 0.2)): -> ValueError: complex(1, 0.1 + 0.2) nincs a sorozatban. Tesztelt sorozat: List([4, 0.3, 4, 0.3, 4, (1+0.3j), (1+0.3j)]) Nincs hiba az index() metódus eredményében. Tesztelt sorozat: (4, 0.3, 4, 0.3, 4, (1+0.3j), (1+0.3j)) Hibák az index() metódus eredményében: index(0.1 + 0.2): -> ValueError: 0.1 + 0.2 nincs a sorozatban. index(complex(1, 0.1 + 0.2)): -> ValueError: complex(1, 0.1 + 0.2) nincs a sorozatban. Tesztelt sorozat: Tuple([4, 0.3, 4, 0.3, 4, (1+0.3j), (1+0.3j)]) Nincs hiba az index() metódus eredményében. Tesztelt sorozat: deque([4, 0.3, 4, 0.3, 4, (1+0.3j), (1+0.3j)]) Hibák az index() metódus eredményében: index(0.1 + 0.2): -> ValueError: 0.1 + 0.2 nincs a sorozatban. index(complex(1, 0.1 + 0.2)): -> ValueError: complex(1, 0.1 + 0.2) nincs a sorozatban. Tesztelt sorozat: Deque([4, 0.3, 4, 0.3, 4, (1+0.3j), (1+0.3j)]) Nincs hiba az index() metódus eredményében. Tesztelt sorozat: array('d', [4.0, 0.3, 4.0, 0.3, 4.0]) Hibák az index() metódus eredményében: index(0.1 + 0.2): -> ValueError: 0.1 + 0.2 nincs a sorozatban. Tesztelt sorozat: Array('d', [4.0, 0.3, 4.0, 0.3, 4.0]) Nincs hiba az index() metódus eredményében. -------------------- remove() metódus teszt -------------------- Tesztelt sorozat: [4, 0.3, 4, 0.3, 4, (1+0.3j), (1+0.3j)] Hibák a remove() metódus végrehajtásakor: remove(0.1 + 0.2): -> ValueError: 0.1 + 0.2 nincs a sorozatban. remove(complex(1, 0.1 + 0.2)): -> ValueError: complex(1, 0.1 + 0.2) nincs a sorozatban. Tesztelt sorozat: List([4, 0.3, 4, 0.3, 4, (1+0.3j), (1+0.3j)]) Nincs hiba a remove() metódus végrehajtásakor. Tesztelt sorozat: deque([4, 0.3, 4, 0.3, 4, (1+0.3j), (1+0.3j)]) Hibák a remove() metódus végrehajtásakor: remove(0.1 + 0.2): -> ValueError: 0.1 + 0.2 nincs a sorozatban. remove(complex(1, 0.1 + 0.2)): -> ValueError: complex(1, 0.1 + 0.2) nincs a sorozatban. Tesztelt sorozat: Deque([4, 0.3, 4, 0.3, 4, (1+0.3j), (1+0.3j)]) Nincs hiba a remove() metódus végrehajtásakor. Tesztelt sorozat: array('d', [4.0, 0.3, 4.0, 0.3, 4.0]) Hibák a remove() metódus végrehajtásakor: remove(0.1 + 0.2): -> ValueError: 0.1 + 0.2 nincs a sorozatban. Tesztelt sorozat: Array('d', [4.0, 0.3, 4.0, 0.3, 4.0]) Nincs hiba a remove() metódus végrehajtásakor. |
Ebben a bejegyzésben érintettük a sorozattípusú konténereket és metódusait, a mixin osztályok alkalmazását, a változtathatatlan (immutable) objektumokat eredményező típusokból való öröklést, az osztálydekorátorok létrehozását és osztályok normál és dinamikus módon történő definiálását. Ezekről a a Python tudásépítés lépésről lépésre című e-könyv következő fejezeteiben lehet részletesen olvasni: „Beépített konténerobjektumok”, „Beépített típusok nyilvános metódusai”, „Osztályok dekorálása”, a „Készétel fogyasztás – a szabványos könyvtár moduljainak használata” fejezeten belül a „Speciális konténer típusok” alfejezet, a „Mágikus metódusok és speciális attribútumok egyéni osztályokban” fejezeten belül „A példányosítási folyamat befolyásolása” alfejezet, a „Különleges osztálydefiníciók” fejezet „Dinamikus típusdefiniálás” alfejezete.