Kako - i zašto - trebate koristiti Python Generators

Generatori su važan dio Pythona otkad su predstavljeni s PEP 255.

Funkcije generatora omogućuju vam deklariranje funkcije koja se ponaša poput iteratora.

Oni omogućuju programerima da naprave iterator na brz, jednostavan i čist način.

Što je iterator, možete se pitati?

Iterator je objekt koji se ponovljena (petlju) na. Koristi se za apstrahiranje spremnika podataka kako bi se ponašao poput iterabilnog objekta. Vjerojatno već koristite nekoliko iterabilnih objekata svaki dan: nizove, popise i rječnike da nabrojite nekoliko.

Iterator je definiran klasom koja implementira Iterator Protocol . Ovaj protokol traži dvije metode unutar klase: __iter__i __next__.

Opa, odmakni se. Zašto biste uopće željeli napraviti iteratore?

Ušteda prostora u memoriji

Iteratori ne izračunavaju vrijednost svake stavke kada je izrađena. Izračunavaju ga samo kad to zatražite. Ovo je poznato kao lijeno vrednovanje.

Lijena procjena korisna je kada imate vrlo velik skup podataka za izračunavanje. Omogućuje vam da odmah počnete koristiti podatke, dok se izračunava cijeli skup podataka.

Recimo da želimo dobiti sve proste brojeve koji su manji od maksimalnog broja.

Prvo definiramo funkciju koja provjerava je li broj prost:

def check_prime(number): for divisor in range(2, int(number ** 0.5) + 1): if number % divisor == 0: return False return True

Zatim definiramo klasu Iterator koji će uključivati __iter__i __next__metode:

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

Primesje instanciran s maksimalnom vrijednošću. Ako je sljedeći prosti broj veći ili jednak od max, iterator će pokrenuti StopIterationiznimku koja završava iterator.

Kada zatražimo sljedeći element u iteratoru, on će se povećati numberza 1 i provjeriti je li to prost broj. Ako nije, nazvat će __next__ponovno dok ne numberpostane glavni. Jednom kad je, iterator vraća broj.

Korištenjem iteratora ne stvaramo popis prostih brojeva u svojoj memoriji. Umjesto toga, generiramo sljedeći prosti broj svaki put kad ga zatražimo.

Isprobajmo:

primes = Primes(100000000000)
print(primes)
for x in primes: print(x)
---------
235711...

Svaka iteracija Primesobjekta poziva __next__na generiranje sljedećeg prostog broja.

Ponavljači se mogu ponoviti samo jednom. Ako pokušate ponoviti postupak primesiznova, vrijednost se neće vratiti. Ponašat će se kao prazan popis.

Sad kad znamo što su iteratori i kako ih napraviti, prijeći ćemo na generatore.

Generatori

Podsjetimo da nam funkcije generatora omogućuju jednostavnije stvaranje iteratora.

Generatori uvode yieldizjavu u Python. Djeluje nekako slično returnjer vraća vrijednost.

Razlika je u tome što se sprema stanje funkcije. Sljedeći put kad se funkcija pozove, izvršenje se nastavlja tamo gdje je stala , s istim vrijednostima varijable koje je imala prije nego što je dala.

Ako svoj Primesiterator pretvorimo u generator, izgledat će ovako:

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

Sad je to prilično pitonično! Možemo li bolje?

Da! Možemo koristiti izraze generatora , uvedene s PEP 289.

Ovo je ekvivalent generatora za razumijevanje popisa. Djeluje točno na isti način kao i razumijevanje popisa, ali je izraz okružen sa ()za razliku od [].

Sljedeći izraz može zamijeniti našu gornju funkciju generatora:

primes = (i for i in range(2, 100000000000) if check_prime(i))
print(primes)
for x in primes: print(x)
---------

    
     235711...
    

Ovo je ljepota generatora u Pythonu.

U sažetku…

  • Generatori vam omogućuju stvaranje iteratora na vrlo pitonski način.
  • Iteratori dopuštaju lijenu procjenu, generirajući samo sljedeći element iterabilnog objekta na zahtjev. Ovo je korisno za vrlo velike skupove podataka.
  • Ponavljači i generatori mogu se ponoviti samo jednom.
  • Funkcije generatora su bolje od iteratora.
  • Generatorski izrazi bolji su od iteratora (samo za jednostavne slučajeve).

Također možete provjeriti moje objašnjenje kako sam pomoću Pythona pronalazio zanimljive ljude koje bih slijedio na Mediumu.

Za više ažuriranja, slijedite me na Twitteru.