Mga Generator sa Python
Ipinaliwanag ng artikulong ito ang mga generator sa Python.
YouTube Video
Mga Generator sa Python
Pangkalahatang-ideya
Ang mga generator ng Python ay isang uri ng iterator at isang kapangyarihang tampok para sa mabisang pagsasagawa ng paulit-ulit na proseso. Pinapayagan ka nitong sumulat ng memory-efficient na code kapag humaharap sa malaking dami ng data.
Ano ang Generator?
Ang generator sa Python ay isang espesyal na function na nagpo-produce ng isang halaga kada tawag, at tinutukoy gamit ang yield
na keyword. Ang katangian nito ay na napapahinto ang execution habang naiingatan ang estado nito, at maaaring ipagpatuloy sa kalaunan.
Pangunahing Kaalaman ukol sa yield
Ang yield
ay isang keyword na nagbabalik ng halaga at sabay na pinapahinto ang pagsasagawa ng function.
1def simple_generator():
2 yield 1
3 yield 2
4 yield 3
5
6gen = simple_generator()
7
8print(next(gen)) # 1
9print(next(gen)) # 2
10print(next(gen)) # 3
- Kapag tinawag, ang function na ito ay nagbabalik ng generator object na nagbibigay ng mga halaga isa-isa.
- Kapag tinawag mo ang
next()
kapag wala nang susunod na halaga, magaganap ang isangStopIteration
na error.
next()
at StopIteration
1def simple_generator():
2 yield 1
3 yield 2
4 yield 3
5
6gen = simple_generator()
7
8try:
9 while True:
10 value = next(gen)
11 print(value)
12except StopIteration:
13 print("Finished")
- Sa pamamagitan ng hayagang paghawak sa error na
StopIteration
gaya nito, maaari mong matukoy kung kailan natapos ang isang generator.
send(value)
Ang pagtawag ng send(value)
ay nagpapatuloy sa generator at ipinapadala ang value
sa posisyon ng yield
expression. Ang ipinadalang halaga ay maaaring matanggap sa panig ng generator bilang return value ng yield
expression. Sa unang tawag, hindi ka maaaring magpadala ng anuman maliban sa None
gamit ang send(value)
, kaya kailangan mong gamitin ang next()
o send(None)
.
1def gen():
2 x = yield 1
3 print(f"x = {x}")
4 y = yield 2
5 print(f"y = {y}")
6
7g = gen()
8print(next(g)) # -> 1 (value from yield 1)
9print(g.send(10)) # -> x = 10, 2 (value from yield 2)
10print(g.send(20)) # -> y = 20, StopIteration occurs
- Sa paggamit ng
send(10)
, angyield
ng generator ay nagiging expression na nagbabalik ng 10, at 10 ang ina-assign sax
.
throw()
Ang pagtawag ng throw
ay nagpapatuloy sa generator at nagbuo ng exception sa posisyon ng naka-pause na yield
. Maari mong hawakan ang exception sa loob ng generator para maipagpatuloy ang pagproseso. Kung ang exception ay hindi nahuli, ito ay lalabas palabas at matatapos ang generator.
1def gen():
2 try:
3 yield 1
4 except ValueError as e:
5 print(f"Caught: {e}")
6 yield "recovered"
7
8g = gen()
9print(next(g)) # -> 1
10print(g.throw(ValueError("boom"))) # -> Caught: boom, "recovered"
- Sa code na ito, tinatawag ang
throw
para magpasok ng exception sa generator. Sa panig ng generator, hinahawakan ang exception atrecovered
ang ibinabalik.
close()
Ang pagtawag ng close()
ay nagtatapos sa generator. Sa loob ng generator, maaari kang magsagawa ng paglilinis gamit ang finally
. Ang pagtawag ng next()
o send()
pagkatapos ng close()
ay magbubunga ng StopIteration
error.
1def gen():
2 try:
3 yield 1
4 finally:
5 print("Cleaning up...")
6
7g = gen()
8print(next(g)) # -> 1
9g.close() # -> Cleaning up...
- Ipinapakita ng code na ito na ang pagtawag ng
close()
ay nagtatapos sa generator at nagpapagana ng proseso ng paglilinis safinally
.
yield from
yield from
ay isang syntax na ginagamit para magdelega sa isang subgenerator. Ito ay isang simpleng paraan para tumawag ng ibang generator sa loob ng isang generator at ipasa ang lahat ng mga halaga nito sa panlabas na scope.
1def sub_gen():
2 yield 1
3 yield 2
4
5def main_gen():
6 yield from sub_gen()
7 yield 3
8
9print(list(main_gen())) # -> [1, 2, 3]
- Ang code na ito ay dine-delegate ang lahat ng halaga mula sa subgenerator papunta sa outer generator gamit ang
yield from
, at pagkatapos ay nag-yi-yield ng3
.
Kaugnayan sa mga Iterator
Ang mga generator ay may sariling implementasyon ng __iter__()
at __next__()
, kaya itinuturing silang isang uri ng iterator. Dahil dito, ganap silang compatible sa mga iterable operations gaya ng for
loop.
Integrasyon sa mga for
Loop
Sa Python, ang for
loop ay gumagamit ng next()
sa loob upang awtomatikong makuha ang mga halaga.
1def simple_generator():
2 yield 1
3 yield 2
4 yield 3
5
6for value in simple_generator():
7 print(value)
Sa pamamaraang ito, awtomatiko ring hinahawakan ang StopIteration
.
Paggawa ng Walang-hanggang Generator
1def count_up(start=0):
2 while True:
3 yield start
4 start += 1
5
6counter = count_up()
7print(next(counter)) # 0
8print(next(counter)) # 1
Maaaring gumawa ng mga walang-hanggang loop, ngunit kailangang mag-ingat sa paggamit nito.
Mga Generator Expression
Ang mga generator expression na sinusulat gamit ang panaklong ay nagbibigay-daan upang makabuo ng generator gamit ang syntax na kahawig ng list comprehension.
1# List comprehension (generates the entire list at once)
2squares_list = [x**2 for x in range(5)]
3print(squares_list)
4
5# Generator expression
6squares_gen = (x**2 for x in range(5))
7for square in squares_gen:
8 print(square)
Hindi tulad ng list comprehensions, hindi nila niloload ang lahat ng elemento sa memorya nang sabay-sabay, kaya mas memory efficient ito.
Paghawak ng Error sa Mga Generator
Maaaring may error na mangyari sa loob ng generator. Sa ganitong mga pagkakataon, gumamit ng try-except
gaya ng regular na Python code.
1def safe_divide_generator(numbers, divisor):
2 """Yields results of dividing numbers by a given divisor safely."""
3 for number in numbers:
4 try:
5 yield number / divisor # Attempt to divide and yield result.
6 except ZeroDivisionError:
7 yield float('inf') # Return infinity if division by zero occurs.
8
9# Example usage
10numbers = [10, 20, 30]
11gen = safe_divide_generator(numbers, 0) # Create generator with divisor as 0.
12for value in gen:
13 print(value) # Output: inf, inf, inf
Sa halimbawang ito, wasto ang paghawak ng error sa kaganapan ng paghahati sa zero.
Stack Trace ng Generator
Kung may nangyaring exception sa loob ng generator, ito ay ilalabas kapag nagpapatuloy ang generator.
1def error_generator():
2 """A generator that yields values and raises an error."""
3 yield 1
4 raise ValueError("An error occurred") # Raise a ValueError intentionally.
5 yield 2
6
7gen = error_generator()
8print(next(gen)) # Output: 1 (first value yielded)
9try:
10 print(next(gen)) # Attempt to get the next value, which raises an error
11except ValueError as e:
12 print(e) # Output: An error occurred (exception message is printed)
- Ang generator na ito ay nagbabalik muna ng
1
. Ang error na lumitaw sa pagpapatuloy ay nasasalo at ipinapakita bilang mensahe ng error.
Mga Halimbawa ng Paggamit ng Generator
Pagbasa ng file kada linya (angkop para sa malalaking file)
1def read_large_file(filepath):
2 with open(filepath, 'r') as f:
3 for line in f:
4 yield line.strip()
- Ang function na ito ay nagbabasa ng isang text file linya kada linya gamit ang iterator, tinatanggal ang whitespace sa bawat linya, at ibinabalik ito bilang generator, kaya maaaring maproseso ang malalaking file na mababa lang ang konsumo sa memorya.
Generator para sa Fibonacci Sequence
1def fibonacci(limit):
2 a, b = 0, 1
3 while a < limit:
4 yield a
5 a, b = b, a + b
6
7for n in fibonacci(100):
8 print(n)
- Gumagamit ang code na ito ng generator upang sunud-sunod na bumuo ng mga Fibonacci na numero na mas mababa sa itinatakdang limitasyon at inilalabas ang mga ito gamit ang isang
for
loop.
Mga Gamit / Use Case
Ang mga generator ay maaari ring magamit sa mga sumusunod na sitwasyon.
- Sunud-sunod na pagproseso ng malalaking CSV o log na mga file
- Pagination sa API
- Pagpoproseso ng streaming data (halimbawa, Kafka, mga IoT device)
Buod
Konsepto | Mahalagang Punto |
---|---|
yield |
Pinapahinto at nagbabalik ng halaga |
Generator Function | Function na may yield at nagbabalik ng iterator kapag tinawag |
Kalamangan | Memory-efficient at mainam para sa malalaking set ng data |
Generator Expression | Nagbibigay-daan sa pinaikling syntax tulad ng (x for x in iterable) |
Sa paggamit ng mga generator, maaari mong iproseso ang malalaking set ng data nang mahusay habang natitipid ang memorya at nananatiling maikli ang iyong code.
Maaari mong sundan ang artikulo sa itaas gamit ang Visual Studio Code sa aming YouTube channel. Paki-check din ang aming YouTube channel.