Pythonイテレータはメモリ効率が非常に高くなります。リストだけでなく、常にジェネレータを使用した方がよいですか?どのような場合に、単純な配列を使用すべきですか?
たとえば、これの代わりに:
emails = [user.email for user in users]
私はこれを好むべきですか?:
emails = (user.email for user in users)
注:「イテレータ」ではなく「ジェネレータ」を意味します。
Pythonイテレータはメモリ効率が非常に高くなります。リストだけでなく、常にジェネレータを使用した方がよいですか?どのような場合に、単純な配列を使用すべきですか?
たとえば、これの代わりに:
emails = [user.email for user in users]
私はこれを好むべきですか?:
emails = (user.email for user in users)
注:「イテレータ」ではなく「ジェネレータ」を意味します。
回答:
ジェネレータの主な欠点は、一方向にしかトラバースできないことです。以前の値に戻ることはありません。それらを共有することもできません。それが簡単に説明できる場合もあれば、それが望ましい場合も多くありますが、そうでない場合も多くあります。たとえば、並べ替え。
そのため、大量のデータの初期処理段階でジェネレーターが使用され、サブセットにフィルター処理されて適切な形式にマップされると、永続的な具象データ構造に組み込まれることがよくあります。さらに使用。これにより、メモリの割り当て、キャッシュミス、ガベージコレクションのコストを、すぐに捨ててしまう大きな中間配列に費やすことがなくなります。
イテレータがジェネレータと混同されています。
最初の例はリスト反復子式で、2番目の例はジェネレータ式です。主な違いは、ジェネレーターは(必要に応じて)即座にではなく(必要に応じて)所定のコレクションの各メンバーを(必要に応じて)遅延して作成することです。returnではなくyieldを使用して、独自のジェネレーターを定義できます。
使用方法に関する限り、それ自体のためのリスト(または辞書など)が必要な場合は、イテレータが必要です。コレクションが最終製品に付随する場合は、ジェネレータを使用します。たとえば、ジェネレータを使用して、いくつかの他の基準からいくつかの基準を満たす数値のリストを取得できます。元のリストは気にせず、基準に一致するメンバーだけが対象です。したがって、ジェネレータを使用して、これらの数値のみを取得します。
より具体的な例は、辺の長さが一定である三角形の角度を見つけることです。私たちはすべての貧しい、変形した三角形が必要なのではなく、強くて健康な三角形だけが欲しいです。したがって、ジェネレータを使用します。
このスタックオーバーフローの投稿では、さらに詳しく説明しています。