生成器本身是一種只能輸出數據的結構,它不像列表或其他容器可以存儲數據並操作。它是一種(lazy evaluation)輸出數據的結構,生成器僅在需要時生成數據。因此,它對於處理大數據集或無限序列時非常高效。
然而,生成器與列表或其他容器不同的一個特點是,生成器通常只能輸出數據,但在某些情況下,我們希望生成器能夠根據外部的輸入來動態生成新的結果。這就是 send()
方法的作用。
在 Python 中,可以通過生成器的 send()
方法向生成器內部傳遞數據。
yield
來返回數據。yield
,它會暫停並返回當前值。下一次調用生成器(通過 next()
或 send()
)時,會從暫停處繼續執行。next()
獲取下一個 yield
的值,還可以用 send(value)
將數據發送給生成器。在 yield
表達式處,生成器會接收到 send()
發送的值並進行處理。def my_generator():
value = 0
while True:
received = yield value
if received is not None:
value = received
else:
value += 1
gen = my_generator()
# 獲取生成器的初始值
print(next(gen)) # Output: 0
# 透過 send() 傳遞數據給生成器
print(gen.send(10)) # Output: 10
# 不傳送數據,生成器繼續計算
print(next(gen)) # Output: 11
next(gen)
:啟動生成器,返回初始值 0
。gen.send(10)
:將 10
傳送給生成器,接收 yield
,此時生成器內部變量 value
被設置為 10
。next(gen)
:當沒有傳送新值時,生成器默認將 value
加 1
,所以輸出為 11
。協程是生成器的擴展,它可以讓你動態接收來自外部的數據並進行處理。
def coroutine_example():
print("協程啟動")
while True:
received = yield
print(f"接收到的數據: {received}")
# 啟動生成器協程
gen = coroutine_example()
next(gen) # 啟動協程
gen.send("第一個數據")
gen.send("第二個數據")
coroutine_example
是一個協程,它通過 yield
暫停,並等待 send()
傳送的數據。每次 send()
傳送後,協程內部會打印接收到的數據。生成器可以用於事件驅動的場景,接收外部事件並根據事件狀態進行操作。
def event_driven_generator():
print('開始接收外部事件')
event_count = 0
while True:
event = yield event_count
if event == "click":
event_count += 1
elif event == "reset":
event_count = 0
print(f"事件數量: {event_count}")
gen = event_driven_generator()
next(gen) # 啟動生成器
# 模擬事件
gen.send("click")
gen.send("click")
gen.send("reset")
gen.send("click")
event_driven_generator
生成器接收不同的事件,例如「click」或「reset」。每次收到「click」事件時,會遞增計數,收到「reset」時重置計數。這個範例展示了如何利用生成器進行數據流處理,動態生成數據而不是一次性加載。
def data_stream_processor(data):
print(f'接收資料')
total = 0
for item in data:
total += item
print(f'處理第{item}個資訊 :{total}')
processed_value = yield total
if processed_value is not None:
total = processed_value
print(f'處理接收的資訊 :{total}')
gen = data_stream_processor([1, 2, 3, 4, 5])
print(next(gen)) # 處理第一個數據
print(gen.send(10)) # 更新總和為 10 並繼續
print(next(gen)) # 繼續處理
print(next(gen)) # 繼續處理
print(gen.send(10)) # 更新總和為 10 並繼續
data
列表作為輸入。total
:這是一個累加變數,初始值為 0,用來計算資料的總和。for item in data
:生成器逐步處理 data
列表中的每個項目,每次迭代會將當前的項目 item
加到 total
中。yield total
:這行代碼會返回目前的 total
值,同時生成器會暫停並等待下一個操作(通過 next()
或 send()
)。processed_value = yield total
:這允許外部使用 send()
方法傳入數據。傳入的數據會賦值給 processed_value
。如果 processed_value
不是 None
,則生成器會更新 total
的值,這樣可以動態調整累加的結果。gen = data_stream_processor([1, 2, 3, 4, 5])
這行程式碼會創建生成器對象 gen
,並將列表 [1, 2, 3, 4, 5]
傳遞給它。
print(next(gen)) # 處理第一個數據
next(gen)
會啟動生成器的執行,並讓它跑到第一個 yield
位置。1
,計算總和 total = 1
,並暫停在 yield
。接收資料
處理第1個資訊 :1
1
print(gen.send(10)) # 更新總和為 10 並繼續
send(10)
,傳入的數值 10
會作為 processed_value
,並影響生成器的執行。processed_value = 10
,所以 total
會更新為 10
,然後繼續處理下一個數據(第 2 項 2
)。total = 10 + 2 = 12
,並暫停在 yield
。處理接收的資訊 :10
處理第2個資訊 :12
12
print(next(gen)) # 繼續處理
next(gen)
,生成器會從暫停處繼續執行,處理第三個數據 3
,總和更新為 total = 12 + 3 = 15
。處理第3個資訊 :15
15
print(next(gen)) # 繼續處理
4
,總和變為 total = 15 + 4 = 19
。處理第4個資訊 :19
19
print(gen.send(10)) # 更新總和為 10 並繼續
send(10)
再次將 total
更新為 10
,然後處理最後一個數據 5
,最終總和變為 total = 10 + 5 = 15
。處理接收的資訊 :10
處理第5個資訊 :15
15
data_stream_processor
逐步處理列表中的數據,並且允許通過 send()
動態修改內部狀態(即 total
)。yield
都會暫停生成器的執行,等待外部的操作(next()
或 send()
),並根據外部數據更新狀態。data_stream_processor
逐步處理列表中的數據,並且允許通過 send()
動態修改內部狀態(即 total
)。yield
都會暫停生成器的執行,等待外部的操作(next()
或 send()
),並根據外部數據更新狀態。