modalsoul’s blog

これは“失敗”と呼べるかもしれないが、ぼくは“学習体験”と呼びたい

Pythonicなリストのfilter処理

Pythonicにリストをfilterするにはどうするか?といい話題がでたので、ちょっと考えてみた


話のもとになったslackの投稿(とその擬似コード

  • パターンA
names = [x for x in names if x is CONDITION]

↑だとxに何が入ってくるのかがわからない

  • パターンB
names = [name for names in names if name is CONDITION]

↑長い

  • パターンC
names = list(filter(lambda x: x is CONDITION, names))

lambda x:の部分はフィルタの関数が定義されているだけなので、xが何かわからなくてもいい?

どれがPythonicで良いコードなのか?


自分個人の見解としてはfilterを使いたい

理由としては、filterのほうがフィルターしていることが明示的だから。

フィルターしていることがわかると、引数にとったリストの要素の型と同じ型の要素を持つリストが帰ってくることが読み取れる

擬似的にScalaで型を表記すると、

val list:List[A]なら、filter(f, list)List[A]であるということ


それと、filterに渡すフィルタの関数の引数が何であるかは気にしなくて良いと思う

フィルターであれば、何が入ってくるかより、何になればフィルターの条件を満たすのかがわかればよくて、極論変数名もいらないと思う

Scalaの場合、関数のすべての引数が1回のみ使われる場合、引数宣言を省略して_で記述できる

ex)

names.filter( _ == HOGE)

なので、Pythonでもこんな風に書きたいくらい

names = list(filter(lambda _: _ is HOGE))

実際これでも動く


最終的にSlack上の議論では、内包表記がよいということになった

理由としては、可読性が良いから

可読性がよいと判断する理由としては、内包表記のほうがより一般的であるため

複数人でメンテナンスするコードであれば、尚更大事なポイント


それと、Effective Pythonでも内包表記を薦めているし

qiita.com

内包表記のほうがfilterの10倍くらい速いらしい