
A generátorok azóta is fontos részei a Pythonnak, amióta bemutatták őket a PEP 255-tel.
A generátor funkciók lehetővé teszik egy olyan funkció deklarálását, amely iterátor módjára viselkedik.
Lehetővé teszik a programozók számára, hogy gyors, egyszerű és tiszta módon készítsenek iterátort.
Mi az iterátor, megkérdezheti?
Az iterátor olyan objektum, amelyre iterálni lehet (hurokba lehet kapcsolni). Egy adattároló elvonására szolgál, hogy iterálható objektumként viselkedjen. Valószínűleg már naponta használ néhány iterálható objektumot: karakterláncokat, listákat és szótárakat, hogy csak néhányat említsünk.
Az iterátort egy olyan osztály határozza meg, amely megvalósítja az Iterator protokollt . Ez a protokoll két módszert keres az osztályon belül: __iter__
és __next__
.
Hé, lépj vissza. Miért is akarna iterátorokat csinálni?
Memóriatakarékosság
Az iterátorok nem számolják az egyes elemek értékét, amikor példányosítják. Csak akkor számolják ki, amikor Ön kéri. Ezt lusta értékelésnek nevezik.
A lusta értékelés akkor hasznos, ha nagyon nagy adathalmaz van a számításhoz. Lehetővé teszi az adatok azonnali használatának megkezdését, miközben a teljes adatsort kiszámítják.
Tegyük fel, hogy meg akarjuk szerezni az összes prímszámot, amely kisebb, mint egy maximális szám.
Először definiáljuk azt a függvényt, amely ellenőrzi, hogy egy szám prím-e:
def check_prime(number): for divisor in range(2, int(number ** 0.5) + 1): if number % divisor == 0: return False return True
Ezután meghatározzuk az iterátor osztályt, amely tartalmazza a __iter__
és __next__
metódusokat:
class Primes: def __init__(self, max): self.max = max self.number = 1
def __iter__(self): return self
def __next__(self): self.number += 1 if self.number >= self.max: raise StopIteration elif check_prime(self.number): return self.number else: return self.__next__()
Primes
maximális értékkel példányos. Ha a következő prím nagyobb vagy egyenlő, mint az max
, az iterátor StopIteration
kivételt vet fel , amely véget vet az iterátornak.
Amikor az iterátor következő elemét kérjük, az number
1-gyel növekszik , és ellenőrzi, hogy ez prímszám-e. Ha nem, akkor újra felhívja __next__
, amíg number
a legfelsőbb. Miután ez megtörtént, az iterátor visszaadja a számot.
Az iterátor használatával nem hozunk létre a prímszámok listáját a memóriánkban. Ehelyett a következő prímszámot generáljuk minden alkalommal, amikor erre kérünk.
Próbáljuk ki:
primes = Primes(100000000000)
print(primes)
for x in primes: print(x)
---------
235711...
Az Primes
objektum minden iterációja felhívja __next__
a következő prímszám előállítását.
Az iterátorokat csak egyszer lehet ismételni. Ha primes
újra megpróbálja megismételni, akkor nem ad vissza értéket. Üres listaként fog viselkedni.
Most, hogy tudjuk, mi az iterátor és hogyan készítsünk ilyet, áttérünk a generátorokra.
Generátorok
Emlékezzünk vissza arra, hogy a generátorfunkciók lehetővé teszik az iterátorok egyszerűbb létrehozását.
A generátorok bemutatják a yield
nyilatkozatot a Pythonnak. Kicsit úgy működik, mint return
mert visszaad egy értéket.
A különbség az, hogy megmenti a függvény állapotát . A következő alkalommal, amikor a függvényt meghívják, a végrehajtás onnan folytatódik, ahol abbahagyta , ugyanazokkal a változóértékekkel, mint amilyenek voltak a hozam előtt.
Ha Primes
iterátorunkat generátorrá alakítjuk, a következőképpen fog kinézni:
def Primes(max): number = 1 while number < max: number += 1 if check_prime(number): yield number
primes = Primes(100000000000)
print(primes)
for x in primes: print(x)
---------
235711...
Ez most elég piton! Jobban tehetnénk?
Igen! Használhatjuk a Generator Expressions kifejezést , amelyet a PEP 289-gyel vezettünk be.
Ez a generátorok felfogási ekvivalense. Pontosan ugyanúgy működik, mint a lista megértése, de a kifejezés körül van vetve ()
, szemben a []
.
A következő kifejezés helyettesítheti a fenti generátorfüggvényünket:
primes = (i for i in range(2, 100000000000) if check_prime(i))
print(primes)
for x in primes: print(x)
---------
235711...
Ez a Python generátorainak szépsége.
Összefoglalva…
- A generátorok lehetővé teszik az iterátorok létrehozását nagyon pythonikus módon.
- Az iterátorok lehetővé teszik a lusta értékelést, csak akkor kérhetők, ha egy iterálható objektum következő elemét generálják. Ez nagyon nagy adathalmazok esetén hasznos.
- Az iterátorokat és generátorokat csak egyszer lehet ismételni.
- A generátorfunkciók jobbak, mint az iterátorok.
- A generátor kifejezések jobbak az iterátoroknál (csak egyszerű esetekben).
Azt is megnézheti, hogy miként használtam a Pythont érdekes emberek követésére a Mediumon.
További frissítésekért kövessen a Twitteren.