魂の生命の領域

AWS とか Python とか本読んだ感想とか哲学とか書きます

Fluent Python メモ~その1~

Fluent Python という 800ページあるクソ分厚い本を読んでいるのですが、この分厚さからも想像がつくようにたいがい腰を据えてじっくり取り組む感じの本です。 ただ、覚えているとすぐに使えそうな内容にもちょいちょい出会うのでこういう場所にメモ代わりに残していきます。

誰に需要があるかというと、俺。 俺が読む。 以上。

list 型をソートする方法として代表的なものが二つあって、list.sort メソッドと組み込み関数の sorted(list) があります。 list.sort メソッドの方は本書で言うところの「インプレイスでソート」します。 コピーは作成されません。 元の list オブジェクトがそのまま変更されます。 こういう場合の戻り値は None にすることが Python API 規約らしいです。

元々のオブジェクトが書き換わってるよ!というのを呼び出し元に明示的に伝えるために、新しいオブジェクトを生成しない(戻り値が None )という仕様にしないといけないということです。

つまりこういうことです。

>>> l = [28, 14, 5, 0, 6, 19]
>>> sorted_l = l.sort()
>>> sorted_l  # None 何も出力されない
>>> l
[0, 5, 6, 14, 19, 28]  # l そのものが書き換わっている

対して組み込み関数の sorted(list) の場合は元の list は変更されずソートされた新しい list オブジェクトを生成します。

>>> l = [28, 14, 5, 0, 6, 19]
>>> sorted_l = sorted(l)
>>> sorted_l
[0, 5, 6, 14, 19, 28]  # ソートされた新しい list が生成される
>>> l
[28, 14, 5, 0, 6, 19]  # 元の list は変更されない

実はこのことをメモに残したかったのではなくて、 sorted(list) には追加で他に引数がセットできるということをメモしたかったのでいきなり話を移します。

  • reverse
    • True なら昇順、 False なら降順で返す
    • デフォルトでは False
>>> l = [28, 14, 5, 0, 6, 19]
>>> sorted_l = sorted(l, reverse=True) 
>>> sorted_l
[28, 19, 14, 6, 5, 0]  # 降順で返す 
  • key
    • ソートするオプションを指定する
    • デフォルトでは identity 関数(普通に比較する)
>>> l = ['hoge', 'foo', 'obama', 'fuga'] 
>>> sorted(l, key=len)
['foo', 'hoge', 'fuga', 'obama']  # 文字列の長さでソート
>>> sorted(l, key=len, reverse=True)     
['obama', 'hoge', 'fuga', 'foo']  # 文字列の長さでソートして逆順に

同じ長さの hogefuga はどちらの順番でソートしようが元の順序を保存します。

んで、keyintstr を指定すると何やら面白いことができそうです。

>>> l = [28, 14, '28', 5, '9', '1', 0, 6, '23', 19]
>>> sorted(l)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '<' not supported between instances of 'str' and 'int'  # 当然だけど型が違うと比較はできない
>>> sorted(l, key=int) 
[0, '1', 5, 6, '9', 14, 19, '23', 28, '28']  # int としてみなしたときの順序
>>> sorted(l, key=str) 
[0, '1', 14, 19, '23', 28, '28', 5, 6, '9']  # str としてみなしたときの順序

何かに使えそうな気がして記事を書き始めたのですが、書いてるうちに何を考えていたのか忘れました。