ASPN : Python Cookbook : Semi-automatic resource management with AutoClose

"Python does not make any guarantee at all about *when* the destructor will be called."というわけで、__del__に書いたコードが想定どおりに動かないケースが紹介されている。
で終了時に確実にインスタンスの後かたづけをするためのレシピ。AutoCloseクラスを継承したクラスを作ってcloseメソッドを実装しておくと、Pythonが終了する時にAutoCloseのクラスメソッドcloseallが呼び出されて、生成した全てのインスタンスのcloseメソッドが実行される。

調べたこと。

  • typeを継承
  • __metaclass__属性
  • __new__メソッド
  • __call__メソッド
  • __subclasses__メソッド
  • atexitモジュール

typeを継承/__metaclass__属性

typeはメタクラス。(=クラス・オブジェクトを生成するクラス。)
静的なクラス定義がなくても動的にクラスを生成することができる。
用例としては、生成するインスタンスを状況に応じて違うクラスのインスタンスにしたり。
使い方は、typeを継承したクラスを別のクラスの__metaclass__属性に入れておく。

__new__メソッド

objectクラスのスタティックメソッド。
__init__はインスタンスが生成された時に呼ばれるが、__new__は生成しよっかなーという時に呼ばれる。
親クラスの__new__を自分で呼び出してやる必要がある。
__new__が結果インスタンスを返すと、それがそのまま__init__に渡る。
コード添削道場のシングルトンの問題で出てた。

サンプルで、AutoCloseMetaの__new__はCやDのクラス宣言時に呼ばれてる。AutoCloseクラスオブジェクトを作るのに必要だから。
mcl._instances.append(cls)は後で使ってる様子がないが何のためだろう。コメントアウトしてもうまく動く。

__call__メソッド

インスタンスを関数みたいに書ける。つまりinstance.__call__(args)の代わりにinstance(args)とできる。
リファレンスによるとそれだけのものだが、メタクラスのメソッドとして定義しておくとインスタンス生成時のコンストラクタ直前に処理を挟めるみたい。
AutoCloseMetaの__call__はCやDの__init__の直前に呼ばれて、後かたづけリストにインスタンスを登録している。

__subclasses__メソッド

ドキュメントが見つからないが、typeクラスのメソッドでサブクラスを全て取得するものらしい。

atexitモジュール

終了ハンドラを扱うモジュール。registerに渡した関数がインタプリタ終了時に実行される。
普通に便利そう。
(追記)簡単にシグナルハンドラの代わりに使えるのかと思ったが、

注意: プログラムがシグナルで停止させられたとき、Python の致命的な内部エラーが検出されたとき、あるいはos._exit()が呼び出されたときには、このモジュールを通して登録した関数は呼び出されません。

とのこと。そっかー。