web-dev-qa-db-ja.com

結果が1つしかない場合は、リスト内包表記の代替

Pythonで理解をリストすることに慣れ始めていますが、私はそれを多少不適切に使用していると思います。リストを使用しているシナリオに数回遭遇しました理解しますが、生成されたリストから最初の(そして唯一の)アイテムをすぐに取得します。次に例を示します。

actor = [actor for actor in self.actors if actor.name==actorName][0]

(self.actorsにはオブジェクトのリストが含まれており、actorNameにある特定の(文字列)名を持つものにアクセスしようとしています。)

私が探しているパラメーターと一致するオブジェクトをリストから引き出しようとしています。この方法は無理ですか?ぶら下がり[0]は少し不安を感じさせます。

66
timfreilly

代わりにジェネレータ式とnextを使用できます。中間リストは作成されず、一致が見つかったら反復を停止できるため、これもより効率的です。

actor = next(actor for actor in self.actors if actor.name==actorName)

senderle が指摘するように、このアプローチの別の利点は、一致が見つからない場合にデフォルトを指定できることです。

actor = next((actor for actor in self.actors if actor.name==actorName), None)
94
zeekay

潜在的に多数の最初の一致を取りたい場合は、next(...)が最適です。ただし、1つだけを期待する場合は、防御的に記述することを検討してください。

[actor] = [actor for actor in self.actors if actor.name==actorName]

これは常に最後までスキャンしますが、[0]とは異なり、[actor]への構造化は、0または複数の一致がある場合にValueErrorをスローします。おそらくバグをキャッチすることよりもさらに重要であり、これは読者にあなたの仮定を伝えます。

0一致のデフォルトが必要であるが、> 1一致をキャッチする場合:

[actor] = [actor for actor in self.actors if actor.name==actorName] or [default]

追伸右側でジェネレータ式を使用することもできます。

[actor] = (actor for actor in self.actors if actor.name==actorName)

ほんの少し効率的です。あなたは左側でタプル構文を使うことができます—より対称的に見えますが、コンマは醜く、IMHOを見逃すには余りにも簡単です:

(actor,) = [actor for actor in self.actors if actor.name==actorName]
actor, = [actor for actor in self.actors if actor.name==actorName]

この投稿 は、うまく機能するカスタムfind()関数と、そこにリンクされているコメンター ジェネレータに基づくこのメソッド があります。基本的に、これを行うための優れた方法は1つではないようですが、これらのソリューションは悪くありません。

2
jtbandes

個人的には、これを適切なループで行います。

actor = None
for actor in self.actors:
    if actor.name == actorName:
        break

かなり長いですが、一致が見つかるとすぐにループが停止するという利点があります。

1
Daniel Roseman