.rute1/

キャリア/心理学/読書/Pythonなどなど

『Pythonトリック』を読んだ

Pythonトリック』が良書だったので紹介します。

Pythonトリック

Pythonトリック

翔泳社のページからPDFでの購入もできます。

私は普段の業務ではRubyを使うことの方が多いのですが、Pythonにも興味があり趣味で書くこともあります。 pythonの言語の仕組みやより良いとされている書き方を勉強したかったのですがFluent Python ―Pythonicな思考とコーディング手法Effective Python 第2版 ―Pythonプログラムを改良する90項目は分厚すぎて尻込みしていたところ こちらの本はコンパクトで立ち読みしたところちょうどよく知りたいことが書かれていた感じだったので購入してみました。

目次

CHAPTER 1 はじめに
1.1 Pythonトリックとは何か
1.2 本書はどのように役立つか
1.3 本書の読み方

CHAPTER 2 よりクリーンなPythonのためのパターン
2.1 アサーションによる安全対策
2.2 無頓着なコンマの配置
2.3 コンテキストマネージャーとwith文
2.4 アンダースコアとダンダー
2.5 文字列のフォーマットに関する衝撃の事実
2.6 「The Zen of Python」の隠しコマンド

CHAPTER 3 効果的な関数
3.1 Pythonの関数はファーストクラスオブジェクト
3.2 ラムダは単一式の関数
3.3 デコレータの威力
3.4 *argsと**kwargs
3.5 引数のアンパック
3.6 ここから返すものは何もない

CHAPTER 4 クラスとオブジェクト指向プログラミング
4.1 オブジェクトの比較:”is”と”==”
4.2 文字列変換:すべてのクラスに_repr_が必要
4.3 カスタム例外クラスを定義する
4.4 趣味と実益を兼ねたクローンオブジェクトの作成
4.5 抽象基底クラスは継承に待ったをかける
4.6 名前付きタプルは何に役立つか
4.7 クラス変数とインスタンス変数の落とし穴
4.8 インスタンスメソッド、クラスメソッド、静的メソッドの謎を解く

CHAPTER 5 Pythonの一般的なデータ構造
5.1 ディクショナリ、マップ、ハッシュテーブル
5.2 配列
5.3 レコード、構造体、DTO
5.4 セットとマルチセット
5.5 スタック(LIFO)
5.6 キュー(FIFO)
5.7 優先度付きキュー

CHAPTER 6 ループとイテレーション
6.1 パイソニックなループの書き方
6.2 内包を理解する
6.3 リストのスライスとすし演算子
6.4 美しいイテレータ
6.5 ジェネレータは単純化されたイテレータ
6.6 ジェネレータ式
6.7 イテレータチェーン

CHAPTER 7 ディクショナリのトリック
7.1 ディクショナリのデフォルト値
7.2 趣味と実益を兼ねたディクショナリのソート
7.3 ディクショナリを使ってswitch/case文をエミュレートする
7.4 型破りなディクショナリ式
7.5 ディクショナリのいろいろなマージ法
7.6 ディクショナリの出力を整える

CHAPTER 8 パイソニックな生産性向上テクニック
8.1 Pythonのモジュールとオブジェクトを調べる
8.2 仮想環境を使ってプロジェクトの依存関係を分離する
8.3 バイトコードの裏側を覗く

CHAPTER 9 最後に
9.1 Python開発者のためのメールマガジン
9.2 PythonistaCafe:Python開発者のコミュニティ

2章は手取り早く役にたつTips集といった感じで、この章だけでも読むとこの本がどんな本かわかると思います。

3章以降は関数、クラス、イテレータ、データ構造などそれぞれのトピックを取り上げて色々なテクニックを紹介する内容になっています。 各章の内容は独立していて、どこから読んでも良いような内容になっているので、とりあえず興味のある章だけ読むという読み方をしても良いと思います。

プログラミング言語初心者でオブジェクト志向はなんとなくわかるというレベルなら4章から、すでに他の言語をある程度理解していてPythonならではの書き方や特徴を知りたいというかたは5~6章、関数型の書き方に興味があるという方は3章がおすすめです。

さらに、各節の最後には内容の簡単な要約もついているので、上級者の場合は最初に要約から読んで知らなった項目だけ読むということもできます。 (私の場合は70%くらいが初めて知る内容でした。)

with文に対応したObjectの作り方

ここからは私が特に面白いと感じた内容について簡単に紹介していきます。

with文はファイル操作などでよく見る書き方です。

with open('hello.txt', 'w') as f:
    f.write('hello, world')

この場合はwithブロックから抜けたらすぐに自動でf.close()を行うことで、安全にリソースを管理することができるようになっています。 with文に対応するオブジェクト(=コンテキストマネージャと呼ばれるらしい)は、このように必ず最初と最後に行いたい処理がある場合に便利な機能です。

実はこのようなコンテキストマネージャは自作クラスや関数でも簡単に作れるようです。
私が試しに考えてみた、環境変数を一時的に変更できる関数を紹介します。

import contextlib
import copy
from os import environ

@contextlib.contextmanager
def env(env: str, value):
    original = copy.copy(environ[env]) # 元の環境変数を保存
    environ[env] = value # 環境変数を上書き
    yield
    environ[env] = original # 元あった値に戻す

# 使い方
print(environ["USER"]) # tarou

with env("USER", "honako"):
    print(environ["USER"]) # hanako

print(environ["USER"]) # tarou

詳しい仕組みはぜひ書籍を読んでいただきたいですが、ざっくりと解説すると、@contextlib.contextmanagerというデコレータを使うことで、 自作のenv関数をwth文に対応させています。
関数の中のyieldまでがwith文の最初に処理される部分、yield以降がwithブロックから抜けた後に実行される処理です。
ここでは最初に既存の環境変数を別の変数に保存し、最後に再び元の環境変数にセットし直すことで一時的に環境変数を変更するということができました。

これ以外にも最初と最後になんらかの処理を実行したいという時にはwith文に対応した関数を使えば書くほうも読む方も楽になりそうなので、便利に使えそうです。

また、この本では関数ではなくオブジェクト(クラス)をwith文に対応させる方法も書かれています。 本の中で宿題として「time.time関数を使ってコードブロックの実行時間を計測するコンテキストマネージャーを実装してみてください」と書かれていたので、 自分なりに考えて実装してみました。

Python stop watch · GitHub

こちらはクラスベースの実装になっていますが、ネタバレになってしまう可能性もあるので心配な方はぜひ書籍を読んでから見てみてください。