更新中Brett Slatkin,Effective Python ―Pythonプログラムを改良する59項目を読む.Pythonを効率的に書くための59のヒントが紹介されている.

特に心に残った項目を以下にまとめる.Jupyter notebookはこちら

1章.Pythonic thinking

リスト内包表記には,3つ以上の式を避ける

リスト内包表記に毒されすぎて,もとの表記の何がわかりづらいのか,また修正された表記でわかりやすくなったのかピンとこない.気をつけないと.

大きな内包表記にはジェネレータ式を考える

イテレータとジェネレータについては,Pythonのイテレータとジェネレータ - Qiitaがわかりやすい.

try/except/else/finallyの各ブロックを活用する

  • except:エラーが補足された場合の処理.
  • else:エラーが捕捉されなかった場合の処理.
  • finally:エラーの捕捉にかかわらず,最後に実行される処理.

2章.関数

Noneを返すよりは例外を選ぶ

Noneと,0や空白文字などの他の値がすべて条件式においてFalseと評価されるため,エラーを引き起こしやすい.それはそうと,raise from構文がよくわからない.あとで確認しよう.

クロージャが変数スコープとどう関わるか知っておく

クロージャとは,関数内の変数の名前解決が,その関数が宣言されたときのスコープで行われるもの.Python Tips: Python でクロージャを使いたい - Life with pythonがとてもわかりやすい.

ちなみにここで登場した特殊メソッド__call__(self)は,クラスのインスタンスを関数っぽく呼び出したときに動作するもの.Pythonのクラスにおける__call__メソッドの使い方 - Qiitaがわかりやすい.

リストを返さずにジェネレータを返すことを考える

これはやってしまいがち.例えばtext中の単語のインデックスを返す関数は次のように定義できる.su

ジェネレータを使うと,リストで返すよりもコードが明確になる.また,作業メモリに全ての入出力を保持する必要がないので,どのような長さの入力に対しても出力シーケンスを生成できる.

引数に対してイテレータを使うときには確実さを尊ぶ

StopIteration例外が起きたあとのジェネレータをもう一度反復した場合,難の例外も発生しない.つまり,出力のないイテレータと,出力があったが尽きてしまったイテレータを区別できない.

よって,関数にイテレータを渡した場合,奇妙な振る舞いや欠損値を生む可能性がある.コンテナとイテレータを区別する方法として,組み込み関数iter()に二度突っ込んで同じ結果が出るか確認する方法がある.

イテレータとジェネレータとコンテナの関係については,Python: ジェネレータをイテレータから理解する - CUBE SUGAR CONTAINERがわかりやすい.

可変長引数を使って,見た目をすっきりさせる

def function(*arg)と定義すると,引数は可変長であり,内部でタプルとして処理される.またdef function(**arg)と定義すると,やはり引数は可変長であり,内部で辞書型として処理される.pythonの引数にある*hogeとか**mapとか - When it’s ready.がわかりやすい.

ちなみに,関数に引数を渡すとき,*listでリスト(タプル)を展開してくれるし,**dictで辞書を展開してくれる.

可変長引数は便利だが,展開時にメモリを大量に消費してしまう可能性がある.引数の入力個数が少ないことがわかっている場合に限って使った方が良い.