เครื่องกำเนิดไฟฟ้าจะทำการประเมินแบบขี้เกียจดังนั้นreturnหรือyieldจะทำงานแตกต่างกันเมื่อคุณทำการดีบั๊กโค้ดของคุณหรือถ้ามีข้อผิดพลาดเกิดขึ้น
ด้วยreturnข้อยกเว้นใด ๆ ที่เกิดขึ้นกับคุณคุณgeneratorจะไม่รู้อะไรเลยgenerate_allนั่นเป็นเพราะเมื่อgeneratorมีการดำเนินการจริง ๆ คุณได้ออกจากgenerate_allฟังก์ชันไปแล้ว ด้วยyieldในนั้นมันจะมีgenerate_allในการย้อนกลับ
def generator(some_list):
for i in some_list:
raise Exception('exception happened :-)')
yield i
def generate_all():
some_list = [1,2,3]
return generator(some_list)
for item in generate_all():
...
Exception Traceback (most recent call last)
<ipython-input-3-b19085eab3e1> in <module>
8 return generator(some_list)
9
---> 10 for item in generate_all():
11 ...
<ipython-input-3-b19085eab3e1> in generator(some_list)
1 def generator(some_list):
2 for i in some_list:
----> 3 raise Exception('exception happened :-)')
4 yield i
5
Exception: exception happened :-)
และถ้ามันใช้yield from:
def generate_all():
some_list = [1,2,3]
yield from generator(some_list)
for item in generate_all():
...
Exception Traceback (most recent call last)
<ipython-input-4-be322887df35> in <module>
8 yield from generator(some_list)
9
---> 10 for item in generate_all():
11 ...
<ipython-input-4-be322887df35> in generate_all()
6 def generate_all():
7 some_list = [1,2,3]
----> 8 yield from generator(some_list)
9
10 for item in generate_all():
<ipython-input-4-be322887df35> in generator(some_list)
1 def generator(some_list):
2 for i in some_list:
----> 3 raise Exception('exception happened :-)')
4 yield i
5
Exception: exception happened :-)
อย่างไรก็ตามสิ่งนี้มาพร้อมกับราคา เลเยอร์ตัวสร้างเพิ่มเติมมีค่าใช้จ่ายบางส่วน ดังนั้นreturnโดยทั่วไปจะเร็วกว่าyield from ...(หรือfor item in ...: yield item) เล็กน้อย ในกรณีส่วนใหญ่สิ่งนี้จะไม่สำคัญมากนักเพราะสิ่งที่คุณทำในเครื่องกำเนิดไฟฟ้ามักจะควบคุมเวลาทำงานเพื่อให้เลเยอร์เพิ่มเติมไม่สามารถสังเกตเห็นได้
อย่างไรก็ตามyieldมีข้อได้เปรียบเพิ่มเติมบางประการ: คุณไม่ได้ จำกัด การทำซ้ำได้เพียงครั้งเดียวคุณยังสามารถเพิ่มรายการเพิ่มเติมได้อย่างง่ายดาย:
def generator(some_list):
for i in some_list:
yield i
def generate_all():
some_list = [1,2,3]
yield 'start'
yield from generator(some_list)
yield 'end'
for item in generate_all():
print(item)
start
1
2
3
end
ในกรณีของคุณการดำเนินการค่อนข้างง่ายและฉันไม่ทราบว่าจำเป็นต้องสร้างฟังก์ชั่นหลายอย่างสำหรับสิ่งนี้หรือไม่เราสามารถใช้ built-in mapหรือ expression ของเครื่องแทนได้อย่างง่ายดาย:
map(do_something, get_the_list()) # map
(do_something(i) for i in get_the_list()) # generator expression
ทั้งสองควรเหมือนกัน (ยกเว้นความแตกต่างบางอย่างเมื่อใช้ข้อยกเว้น) และหากพวกเขาต้องการชื่อที่มีความหมายมากกว่านี้คุณก็สามารถสรุปได้ในฟังก์ชันเดียว
มีผู้ช่วยหลายคนที่รวมการดำเนินการทั่วไปไว้ใน iterables ในตัวและสามารถพบได้ในitertoolsโมดูลในตัว ในกรณีที่เรียบง่ายเช่นนี้ฉันจะหันไปใช้สิ่งเหล่านี้และเฉพาะกรณีที่ไม่สำคัญเขียนเครื่องปั่นไฟของคุณเอง
แต่ฉันคิดว่ารหัสจริงของคุณมีความซับซ้อนมากขึ้นเพื่อที่จะไม่สามารถใช้งานได้ แต่ฉันคิดว่ามันจะไม่เป็นคำตอบที่สมบูรณ์โดยไม่ต้องพูดถึงทางเลือกอื่น