Generator malas mengevaluasi sehingga returnatau yieldakan berperilaku berbeda ketika Anda men-debug kode Anda atau jika ada pengecualian.
Dengan returnpengecualian yang terjadi di Anda generatortidak akan tahu apa-apa generate_all, itu karena ketika generatorbenar-benar dieksekusi Anda telah meninggalkan generate_allfungsi. Dengan yielddi sana akan ada generate_alldi traceback.
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 :-)
Dan jika menggunakan 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 :-)
Namun ini datang pada biaya kinerja. Lapisan generator tambahan memang memiliki beberapa overhead. Jadi returnumumnya akan sedikit lebih cepat daripada yield from ...(atau for item in ...: yield item). Dalam kebanyakan kasus ini tidak akan terlalu menjadi masalah, karena apa pun yang Anda lakukan di generator biasanya mendominasi run-time sehingga lapisan tambahan tidak akan terlihat.
Namun yieldmemiliki beberapa keuntungan tambahan: Anda tidak terbatas pada satu iterable saja, Anda juga dapat dengan mudah menghasilkan item tambahan:
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
Dalam kasus Anda, operasinya cukup sederhana dan saya tidak tahu apakah perlu membuat beberapa fungsi untuk ini, orang dapat dengan mudah menggunakan built-in mapatau ekspresi generator sebagai gantinya:
map(do_something, get_the_list()) # map
(do_something(i) for i in get_the_list()) # generator expression
Keduanya harus identik (kecuali untuk beberapa perbedaan ketika pengecualian terjadi) untuk digunakan. Dan jika mereka membutuhkan nama yang lebih deskriptif, maka Anda masih bisa membungkusnya dalam satu fungsi.
Ada beberapa pembantu yang membungkus operasi yang sangat umum pada iterables bawaan dan yang lebih lanjut dapat ditemukan dalam itertoolsmodul bawaan. Dalam kasus sederhana seperti itu saya hanya akan menggunakan ini dan hanya untuk kasus non-sepele tulis generator Anda sendiri.
Tapi saya menganggap kode Anda yang sebenarnya lebih rumit sehingga mungkin tidak berlaku tetapi saya pikir itu tidak akan menjadi jawaban yang lengkap tanpa menyebutkan alternatif.