Hogyan ellenőriznéd, hogy iterálható-e egy objektum?

Iterálható objektumokról és iterátorokról már bizonyára hallottál, sőt használtad is azokat. Ilyenek többek között azok, amelyekből egy forciklusban sorban egymás után elemeket lehet kikérni. (Ha esetleg nem találkoztál még ezekkel, mert még a Python tanulásod elején tartasz, akkor ajánlatos velük minél korábban alaposan megismerkedni, mert az iterálható objektum és iterátor kulcsfontosságú fogalmak és nyelvi elemek a Pythonban, ezért lépten-nyomon találkozni fogsz velük.)

Általában az többnyire ismert, hogy iterálható egy objektum (legyen a jele x), ha az implementálja az __iter__ metódust. Ezért arra a kérdésre hogy hogyan kell az iterálhatóságot ellenőrizni, jöhet rögtön a válasz, hogy a hasattr(x, ‘__iter__’) beépített függvény eredménye alapján. Ez megvizsgálja, hogy az objektum rendelkezik-e az __iter__ metódussal és ennek megfelelően True vagy False értékkel tér vissza.

Egy másik válasszal is lehet találkozni azoktól, akik már ismerik az absztrakt osztályokat és a collactions.abc modult. Ők azt mondhatják, hogy egy isinstance(x, Iterable) hívással kell ellenőrizni, hogy az x Iterable típusú-e.

Nyilván nem lenne érdemes egy bejegyzést szánni a kérdésnek, ha ezek lennének a teljesen helyes válaszok, és ilyen egyszerűen el lehetne intézni a dolgot. Valójában egy „minden bogár rovar, de nem minden rovar bogár” jellegű témáról van szó.

Az igaz, hogy minden olyan objektum, amely implementálja az __iter__ metódust az iterálható. De az már nem, hogy minden iterálható objektumnak rendelkeznie kell az __iter__ metódussal.

Mely objektumok azok, amelyek nem definiálják az __iter__ metódust és mégis iterálhatók?

Nos, azok, amelyekre implementált, és így meghívható a __getitem__ metódus. Ez indexet, index szeletet vagy kulcsot fogad, és ennek alapján adja vissza a megfelelő elemet.

Ennek alapján az absztrakt osztályokban kicsit járatosabbak most azt mondhatnák, hogy rendben, semmi gond, akkor el kell végezni a típusellenőrzést arra vonatkozóan is, hogy sorozat vagy leképzés típusú-e az x objektum, vagyis meg kell hívni az isinstance(obj, Sequence) és az isinstance(obj, Mapping) függvényeket. Mindezt azon indokkal, mert mind a sorozat mind a leképzés típus definiálja a __getitem__ metódust. Bár ez igaz, de a válasz mégsem helyes, mert mind a Sequence, mind a Mapping definiálja az __iter__ metódust is.

Mindennek illusztrálására egy programot láthatunk alább, amelyben egy olyan osztályt definiáltunk, amelyben csak a __getitem__ implementált, az __iter__ nem. Ha kipróbáljuk, tapasztalhatjuk, hogy egy ciklusba helyezve ez is hiba nélkül kiadja az elemeket. A kiválasztott sorozat, leképzés és halmaz típusú objektumokkal való összevetést az utána levő táblázatban elemezhetjük.

 IterableSequenceMapping__iter____getitem__
list
range
dict
set
Indexelhető

A fent említett okok miatt hívja fel a figyelmet a Python hivatalos dokumentációja arra, hogy az egyetlen megbízható módszer az objektum iterálhatóságának megállapítására az iter(x) hívás. Ez TypeError kivételt fog dobni, ha az x nem iterálható.

Tehát, ha egy objektum iterálhatóságát akarjuk biztonsággal és egyszerű módon megállapítani, akkor az iter() beépített függvényt kell rá meghívni egy try…except… kivételkezelő szerkezetben.

A Python tudásépítés lépésről lépésre című e-könyvben e témakör is részletesen, gyakorlati példákon keresztül bemutatásra kerül.

É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.