Anda dapat menggunakan return
sekali di generator; itu menghentikan iterasi tanpa menghasilkan apa pun, dan dengan demikian memberikan alternatif eksplisit untuk membiarkan fungsi kehabisan ruang lingkup. Jadi gunakan yield
untuk mengubah fungsi menjadi generator, tetapi awali dengan return
menghentikan generator sebelum menghasilkan apa pun.
>>> def f():
... return
... yield
...
>>> list(f())
[]
Saya tidak yakin itu jauh lebih baik dari yang Anda miliki - itu hanya menggantikan if
pernyataan tidak ada operasi dengan pernyataan tidak ada operasi yield
. Tapi itu lebih idiomatis. Perhatikan bahwa hanya menggunakan yield
tidak berhasil.
>>> def f():
... yield
...
>>> list(f())
[None]
Mengapa tidak digunakan saja iter(())
?
Pertanyaan ini menanyakan secara khusus tentang fungsi generator yang kosong . Untuk alasan itu, saya menganggapnya sebagai pertanyaan tentang konsistensi internal sintaksis Python, daripada pertanyaan tentang cara terbaik untuk membuat iterator kosong secara umum.
Jika pertanyaan sebenarnya tentang cara terbaik untuk membuat iterator kosong, maka Anda mungkin setuju dengan Zectbumo tentang penggunaan iter(())
. Namun, penting untuk diperhatikaniter(())
tidak mengembalikan fungsi! Ini secara langsung mengembalikan iterable kosong. Misalkan Anda bekerja dengan API yang mengharapkan callable yang mengembalikan iterable. Anda harus melakukan sesuatu seperti ini:
def empty():
return iter(())
( Penghargaan harus diberikan kepada Unutbu karena memberikan versi pertama yang benar dari jawaban ini.)
Sekarang, Anda mungkin menemukan penjelasan di atas lebih jelas, tetapi saya bisa membayangkan situasi di mana itu menjadi kurang jelas. Pertimbangkan contoh daftar panjang definisi fungsi generator (dibuat-buat) ini:
def zeros():
while True:
yield 0
def ones():
while True:
yield 1
...
Di akhir daftar panjang itu, saya lebih suka melihat sesuatu yang mengandung a yield
, seperti ini:
def empty():
return
yield
atau, dengan Python 3.3 dan yang lebih baru (seperti yang disarankan oleh DSM ), ini:
def empty():
yield from ()
Kehadiran yield
kata kunci membuatnya jelas sekilas bahwa ini hanyalah fungsi generator, persis seperti yang lainnya. Perlu waktu lebih lama untuk melihat bahwa iter(())
versi tersebut melakukan hal yang sama.
Ini perbedaan yang halus, tapi sejujurnya menurut saya yield
fungsi berbasis lebih mudah dibaca dan dipelihara.
if False: yield
tetapi masih agak membingungkan bagi orang-orang yang tidak mengetahui pola iniitertools.empty()
.return
berarti sesuatu yang berbeda di dalam generator. Ini lebih sepertibreak
.False
.Anda tidak membutuhkan generator. Ayo teman-teman!
sumber
iter([])
fakta sederhana yang()
konstan sementara[]
dapat membuat contoh objek daftar baru dalam memori setiap kali dipanggil.empty = lambda: iter(())
ataudef empty(): return iter(())
.tuple_iterator
bukangenerator
. Jika Anda memiliki kasus di mana generator Anda tidak perlu mengembalikan apa pun, jangan gunakan jawaban ini.Python 3.3 (karena saya sedang
yield from
bersemangat, dan karena @senderle mencuri pikiran pertama saya):Tetapi saya harus mengakui, saya kesulitan menemukan kasus penggunaan untuk ini yang mana
iter([])
atau(x)range(0)
tidak akan bekerja sama baiknya.sumber
return; yield
atauif False: yield None
.iter([])
atau(x)range(0)
tidak akan bekerja sama baiknya." -> Tidak yakin apa(x)range(0)
itu, tetapi kasus penggunaan bisa menjadi metode yang dimaksudkan untuk diganti dengan generator yang lengkap di beberapa kelas yang diturunkan. Untuk tujuan konsistensi, Anda bahkan ingin yang basis, dari mana orang lain mewarisi, untuk mengembalikan generator seperti yang menimpanya.Pilihan lainnya adalah:
sumber
Generator[str, Any, None]
Apakah itu fungsi generator? Jika tidak, bagaimana dengan
sumber
Cara "standar" untuk membuat iterator kosong tampak seperti iter ([]). Saya menyarankan untuk membuat [] argumen default ke iter (); ini ditolak dengan argumen yang bagus, lihat http://bugs.python.org/issue25215 - Jurjen
sumber
Seperti yang dikatakan @senderle, gunakan ini:
Saya menulis jawaban ini sebagian besar untuk membagikan pembenaran lain untuk itu.
Salah satu alasan untuk memilih solusi ini di atas yang lain adalah karena solusi ini optimal sejauh menyangkut penafsir.
Seperti yang bisa kita lihat, the
empty_return
memiliki bytecode yang sama persis dengan fungsi kosong biasa; sisanya melakukan sejumlah operasi lain yang tidak mengubah perilakunya. Satu-satunya perbedaan antaraempty_return
dannoop
adalah bahwa yang pertama memiliki set flag generator:Tentu saja, kekuatan argumen ini sangat bergantung pada implementasi khusus Python yang digunakan; juru bahasa alternatif yang cukup cerdas mungkin memperhatikan bahwa operasi lain tidak berguna dan mengoptimalkannya. Namun, meskipun ada pengoptimalan seperti itu, pengoptimalan tersebut memerlukan waktu untuk melaksanakannya dan untuk menjaga agar asumsi pengoptimalan tidak rusak, seperti
iter
pengenal pada cakupan global yang dipantulkan ke sesuatu yang lain (meskipun kemungkinan besar akan menunjukkan bug jika itu sebenarnya terjadi). Dalam halempty_return
tidak ada yang bisa dioptimalkan, jadi CPython yang relatif naif tidak akan membuang waktu untuk operasi palsu.sumber
sumber
Saya ingin memberikan contoh berbasis kelas karena kami belum memiliki saran apa pun. Ini adalah iterator yang dapat dipanggil yang tidak menghasilkan item. Saya yakin ini adalah cara langsung dan deskriptif untuk menyelesaikan masalah.
sumber