Hogyan - és miért kell használnia a Python Generatorokat?

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__()

Primesmaximális értékkel példányos. Ha a következő prím nagyobb vagy egyenlő, mint az max, az iterátor StopIterationkivételt vet fel , amely véget vet az iterátornak.

Amikor az iterátor következő elemét kérjük, az number1-gyel növekszik , és ellenőrzi, hogy ez prímszám-e. Ha nem, akkor újra felhívja __next__, amíg numbera 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 Primesobjektum 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 yieldnyilatkozatot a Pythonnak. Kicsit úgy működik, mint returnmert 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 Primesiterá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.