Mikuláš je tu! Získaj 90 % extra kreditov ZADARMO s promo kódom CERTIK90 pri nákupe od 1 199 kreditov. Len do nedele 7. 12. 2025! Zisti viac:
NOVINKA: Najžiadanejšie rekvalifikačné kurzy teraz s 50% zľavou + kurz AI ZADARMO. Nečakaj, táto ponuka dlho nevydrží! Zisti viac:

5. diel - Iterátory v Pythone

V predchádzajúcom cvičení, Riešené úlohy k 2.-4. lekcii kolekcií v Pythone, sme si precvičili získané skúsenosti z predchádzajúcich lekcií.

V tomto tutoriáli kolekcií v Pythone sa zameriame na iterovateľné objekty a ich dôležitú podmnožinu - iterátory.

Iterovateľný objekt

Pomocou iterácie môžeme postupne získať prvky uložené v nejakej kolekcii (napríklad aplikácií cyklu for na zoznam). Iterovateľný objekt je potom taký objekt, na ktorom je možné vykonať iteráciu. Prvky získame buď v pevne stanovenom poradí (zoznam) alebo v poradí náhodnom (množina).

Iterátory v Pythone nám poskytujú výhodnú možnosť postupne spracovávať veľké množstvo dát, čo je obzvlášť užitočné pri práci s veľkými súbormi alebo dátovými prúdmi. Tieto nástroje nám umožňujú efektívnejšie organizovať naše kódy tým, že umožňujú použitie slučky for s rôznymi iterovateľnými objektmi, ako sú zoznamy, množiny, slovníky a súbory, pričom je dôležité si uvedomiť, že pri ich použití v slučke for Python automaticky vytvára iterátory z týchto iterovateľných štruktúr. Ďalej iterátory podporujú koncept lenivého vyhodnocovania, čo znamená, že prvky sú generované a spracovávané iba v okamihu, keď sú skutočne potrebné, čo v niektorých prípadoch výrazne zlepšuje výkon. V tejto lekcii sa podrobnejšie zoznámime s iterátormi v Pythone, naučíme sa, ako ich správne vytvárať a používať na efektívne spracovanie dát a preskúmame rôzne scenáre ich praktického využitia.

Iterátor

Iterátor je zodpovedný za iteráciu na iterovateľnom objekte. Pamätá si, ktoré prvky už poskytol (neposkytne jeden prvok dvakrát). Vo chvíli, keď už nie je ďalší prvok k dispozícii, nám to oznámi.

V tomto okamihu jeho úloha v programe končí, iterátor je tzv. vyčerpaný (exhausted). Ak chceme znova iterovať, musíme vytvoriť nový iterátor.

Trieda iterovateľného objektu musí implementovať špeciálnu metódu __iter__(), ktorá po zavolaní vytvorí a vráti novú inštanciu triedy Iterator (vytvorí nový "nevyčerpaný" iterátor). Metódu môžeme volať cez vstavanú funkciu iter().

Trieda iterátora potom musí implementovať špeciálnu metódu __iter__(), ktorá ale vracia odkaz na svoju inštanciu – self (nevytvára novú inštanciu). Zároveň musí mať implementovanú metódu __next__(), ktorá po zavolaní vráti ďalší prvok z kolekcie. Ak už nie je ďalší prvok k dispozícii, vyvolá StopIteration výnimku. Metódu je možné volať vstavanou funkciou next().

Je teda veľký rozdiel, či iterujeme na iterovateľnom objekte (napr. zozname), ktorý zavolaním funkcie iter() vracia zakaždým nový iterátor, alebo priamo na iterátore, ktorý vracia iba sám seba.

Technicky je síce iterátor zároveň iterovateľný objekt (obaja implementujú metódu __iter__()). My ich ale budeme v tejto lekcii rozlišovať a ak budeme hovoriť o iterovateľnom objekte, budeme tým myslieť iterovateľný objekt, ktorý nie je zároveň iterátorom.

Cyklus for pod pokrievkou

Než sa vrhneme na praktické príklady, pozrime sa ešte, ako funguje cyklus for, ktorý je z hľadiska iterácie kľúčový. Python totiž v skutočnosti aplikuje cyklus while pomocou nasledujúceho mechanizmu:

my_list = [1, 2, 3, 4, 5]

iterator = iter(my_list)

try:
    while True:
        element = next(iterator)
except StopIteration:
    pass

Na začiatku zavolá funkciu iter() a dostane iterátor. Potom na ňom opakovane volá funkciu next() a získava jednotlivé prvky kým nenarazí na StopIteration výnimku. To sa dá jednoducho overiť. Vytvoríme si vlastnú triedu MyList z triedy list a iba jej ľahko upravíme metódu __iter__(), aby sme vedeli, kedy bola volaná:

class MyList(list):
    def __iter__(self):
        print("Method __iter__() called")
        return super().__iter__()

Teraz vytvoríme jej inštanciu a použijeme cyklus for:

grades = MyList([1, 2, 3])

for element in grades:
    print(element)

Vo výstupe vidíme, že pred vypisovaním jednotlivých prvkov je zavolaná metóda __iter__():

Konzolová aplikácia
Method __iter__() called
1
2
3

Vstavané iterovateľné objekty a iterátory

Doteraz prebranú látku si najskôr vyskúšame na nami dobre známom zozname (objekte typu list). Vytvoríme jeho inštanciu a dvakrát po sebe necháme vypísať všetky jeho prvky:

horrors = ["Alien", "Frankenstein", "Thing"]

for horror in horrors:
    print(horror)

for horror in horrors:
    print(horror)

Všetko prebehlo v poriadku, pretože zoznam je iterovateľný objekt:

Konzolová aplikácia
Alien
Frankenstein
Thing
Alien
Frankenstein
Thing

Túto skutočnosť si zároveň môžeme overiť napríklad použitím vstavanej funkcie dir(), ktorá vracia zoznam atribútov príslušného objektu:

print("__iter__" in dir(horrors), "__next__" in dir(horrors))

Vo výstupe vidíme:

Konzolová aplikácia
(True, False)

Je teda zrejmé, že trieda list má definovanú metódu __iter__() ale nie metódu __next__(). Zavolaním funkcie iter() na náš zoznam získame jeho iterátor. Keďže zoznam je iterovateľný objekt, mal by vrátiť novú inštanciu iterátora, teda nie len odkaz na seba:

print(iter(horrors) is horrors)

Vo výstupe vidíme:

Konzolová aplikácia
False

Všetko teda prebieha podľa očakávania. Teraz si znova vytvoríme iterátor a uložíme si naň odkaz do premennej. Môžeme volať funkciu next(), poprípade metódu __next__() a získať postupne jeho prvky:

horror_iterator = iter(horrors)
print(next(horror_iterator))
print(horror_iterator.__next__())

Vo výstupe vidíme:

Konzolová aplikácia
Alien
Frankenstein

V tom istom kóde môžeme ďalej použiť aj cyklus for. Len musíme pamätať na to, že iterátor sa postupne vyčerpáva:

for horror in horror_iterator:
    print(horror)

Výstup:

Konzolová aplikácia
Thing

Keďže sme prvé dva prvky získali funkciou next(), cyklus for nám vrátil iba posledný prvok. Teraz je iterátor vyčerpaný a ak by sme chceli znova iterovať, museli by sme buď iterovať na pôvodnom zozname (ktorý si príslušný iterátor vytvorí sám automaticky) alebo si iterátor znova explicitne vytvoriť sami zavolaním funkcie iter().

Python ponúka niekoľko užitočných funkcií, ktoré vracajú iterovateľné objekty alebo iterátory. Pozrime sa na ne.

range()

Funkcia range() vracia objekt range, čo je iterovateľný objekt:

r = range(5)

print("__iter__" in dir(r), "__next__" in dir(r))

print(iter(r) is r)

Výstup:

Konzolová aplikácia
True False
False

Z výpisu je zrejmé, že objekt range má implementovanú iba metódu __iter__(), ktorá pred každou iteráciou vytvorí novú inštanciu iterátora. Iterovať na objekte range môžeme tým pádom bez obmedzenia:

print("First iteration:", end=" ")

for number in r:
    print(number, end=", ")

print("\n\nNext iteration:", end=" ")

for number in r:
    print(number, end=", ")

Vo výstupe vidíme:

Konzolová aplikácia
First iteration: 0, 1, 2, 3, 4,

Next iteration: 0, 1, 2, 3, 4,

enumerate()

Oproti tomu funkcia enumerate() vracia objekt enumerate, čo je iterátor. Tento objekt má implementovanú ako metódu __iter__(), tak metódu __next__(). Funkcia iter() vracia ten istý objekt:

e = enumerate(["Homer", "Moe", "Lenny", "Carl"])

print("__iter__" in dir(e), "__next__" in dir(e))

print(iter(e) is e)

Výstup:

Konzolová aplikácia
True True
True

Iterovať na objekte enumerate môžeme maximálne raz. Funkcia enumerate() vytvorí dvojice, kde prvou položkou je index a druhou položkou je príslušný prvok zadaného iterovateľného objektu:

e = enumerate(["Homer", "Moe", "Lenny", "Carl"])
print("First iteration:", end=" ")

for character in e:
    print(character, end=", ")

print("\n\nNext iteration:", end=" ")

for character in e:
    print(character, end=", ")

Vo výstupe vidíme:

Konzolová aplikácia
First iteration: (0, 'Homer'), (1, 'Moe'), (2, 'Lenny'), (3, 'Carl'),

Next iteration:

Na záver si ukážme tabuľku najčastejšie používaných funkcií, ktoré vracajú iterovateľné objekty alebo iterátory:

Funkcie vracajúci iterovateľný objekt Funkcie vracajúci iterátor
list() enumerate()
tuple() zip()
set() map()
dict() filter()
dict.keys() open()
dict.values()  
dict.items()  
range()  

To by bolo k tejto lekcii všetko.

V nasledujúcej lekcii, Iterátory druhýkrát - Generátory v Pythone, si vytvoríme vlastný iterátor, zoznámime sa s generátormi a preskúmame ich výhody.


 

Predchádzajúci článok
Riešené úlohy k 2.-4. lekcii kolekcií v Pythone
Všetky články v sekcii
Kolekcie v Pythone
Preskočiť článok
(neodporúčame)
Iterátory druhýkrát - Generátory v Pythone
Článok pre vás napísal gcx11
Avatar
Užívateľské hodnotenie:
95 hlasov
(^_^)
Aktivity