Saya punya generator generator
dan juga metode kenyamanan untuk itu - generate_all
.
def generator(some_list):
for i in some_list:
yield do_something(i)
def generate_all():
some_list = get_the_list()
return generator(some_list) # <-- Is this supposed to be return or yield?
Haruskah generate_all
return
atau yield
? Saya ingin para pengguna kedua metode untuk menggunakannya sama, yaitu
for x in generate_all()
harus sama dengan
some_list = get_the_list()
for x in generate(some_list)
Jawaban:
Generator malas mengevaluasi sehingga
return
atauyield
akan berperilaku berbeda ketika Anda men-debug kode Anda atau jika ada pengecualian.Dengan
return
pengecualian yang terjadi di Andagenerator
tidak akan tahu apa-apagenerate_all
, itu karena ketikagenerator
benar-benar dieksekusi Anda telah meninggalkangenerate_all
fungsi. Denganyield
di sana akan adagenerate_all
di traceback.Dan jika menggunakan
yield from
:Namun ini datang pada biaya kinerja. Lapisan generator tambahan memang memiliki beberapa overhead. Jadi
return
umumnya akan sedikit lebih cepat daripadayield from ...
(ataufor 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
yield
memiliki beberapa keuntungan tambahan: Anda tidak terbatas pada satu iterable saja, Anda juga dapat dengan mudah menghasilkan item tambahan:Dalam kasus Anda, operasinya cukup sederhana dan saya tidak tahu apakah perlu membuat beberapa fungsi untuk ini, orang dapat dengan mudah menggunakan built-in
map
atau ekspresi generator sebagai gantinya: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
itertools
modul 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.
sumber
Anda mungkin mencari Delegasi Generator (PEP380)
Ini cukup ringkas dan juga memiliki sejumlah keunggulan lain, seperti dapat rantai rantai yang sewenang-wenang / berbeda!
sumber
list
? Ini contoh yang buruk, bukan kode asli yang ditempelkan dalam pertanyaan, saya mungkin harus mengeditnya.yield from map(do_something, iterable)
atau bahkanyield from (do_something(x) for x in iterable)
yield from
tidak ada gunanya kecuali pembungkus Anda melakukan sesuatu yang lain generator-y.return generator(list)
lakukan apa yang kamu inginkan. Tapi perhatikan ituakan setara, tetapi dengan kesempatan untuk menghasilkan lebih banyak nilai setelah
generator
habis. Sebagai contoh:sumber
yield from
danreturn
ketika konsumen generatorthrows
pengecualian di dalamnya - dan dengan operasi lain yang dipengaruhi oleh jejak tumpukan.Dua pernyataan berikut akan tampak setara secara fungsional dalam kasus khusus ini:
dan
Nantinya kira-kira sama dengan
The
return
pernyataan mengembalikan generator yang Anda cari. Sebuahyield from
atauyield
pernyataan ternyata seluruh fungsi Anda menjadi sesuatu yang kembali generator, yang melewati salah satu yang Anda cari.Dari sudut pandang pengguna, tidak ada perbedaan. Namun secara internal,
return
ini bisa dibilang lebih efisien karena tidak membungkusgenerator(list)
generator pass-thru yang berlebihan. Jika Anda berencana untuk melakukan setiap proses pada unsur-unsur dari generator dibungkus, menggunakan beberapa bentukyield
tentu saja.sumber
Anda akan
return
melakukannya.yield
ing * akan menyebabkangenerate_all()
mengevaluasi ke generator itu sendiri, dan memanggilnext
generator luar itu akan mengembalikan generator batin yang dikembalikan oleh fungsi pertama, yang bukan yang Anda inginkan.*
Tidak termasukyield from
sumber