何かを書き留める何か

数学や読んだ本について書く何かです。最近は社会人として生き残りの術を学ぶ日々です。

『Effective Python』Item 16: リストを返す代わりにジェネレータを検討しよう

『Effective Python』の続き。ジェネレータ便利みんな使おう。 www.effectivepython.com

まだ翻訳したのはItem 16までであるが、『Effective Python』には大きく2つのテーマがあると思う。

  1. ビジュアルノイズを減らせ
  2. メモリ不足を防ぐ

ただ単に、この2つの要素が複数回目に入っただけでもしかしたら別のテーマが根底にある、たとえば、Zen of Pythonとか、かもしれない。 特に 1 はZen of Pythonっぽいことがらである。

この「Item 16: リストを返す代わりにジェネレータを検討しよう」は2つのテーマを考える好例である。 文字列が与えられたときに各単語の開始位置のインデックスを調べたい、という状況があったときに、よく次のようなコードを書く。

def index_words(text):
    result = []
    if text:
        result.append(0)
    for index, letter in enumerate(text):
        if letter == ' ':
            result.append(index + 1)
    return result

筆者はこのコードの問題点として大事なところ、今回知りたいはずの各単語の開始位置のインデックスが埋もれてわかりづらいと看破する。 そしてジェネレータを用いて次のように改良する。

def index_words_iter(text):
    if text:
        yield 0
    for index, letter in enumerate(text):
        if letter == ' ':
            yield index + 1

このコードは各単語の開始位置のインデックスを調べたい、という知りたいことだけを削り出している。かなり綺麗なコードである。 中々感動的な改良である。勿論、必要ならば簡単にリストに変換できるので機能面でも不足がないどころかメモリの問題も回避している。 本当に素晴らしい例である。

『Effective Python』Item 17: 引数によるイテレーションは防御的に行う

『Effective Python』の続き。イテレータは使い捨て。 www.effectivepython.com

イテレータは状態を持っている(ステートフル)ので、「使い終わった」という状態が存在する。また、「使い終わった」と「元々何も無い」が区別できない(どちらもStopIteration例外を送出するだけなので)。何度も使いたい場合はコンテナクラスを定義しておこう、という話やそもそも生イテレータを受け付けない、という対策を打つといった方法がある。

この章はサンプルがまるごと掲載されているので気になる方は読んでいただきたい。 www.effectivepython.com

この手のバグ?は結構悩まされていたが、こういうことだったのかとわかってうれしかった思い出がある。このサンプルを翻訳してこのブログに公開しようとしたのがこの一連の記事のきっかけである。何とか、合法的に公開したいのだが上手い方法はあるだろうか。