最近、「ツールを作成する時は、原則 Python を使うこと」というお達しが会社から来た。
各個人がツール作成に使用する言語を統一して、会社としての効率を上げることが目的らしい。

今まではツール作成には Ruby を使用していたが、そんな分けで Python の勉強を始めた今日この頃。
そして、早速だが class の多重継承時の挙動について壁にぶつかった。
いわゆる、「菱形の継承」というやつだ。

菱形の問題に入る前に、Python の継承について確認。

まず、Python は多重継承が可能だ。
クラス A と B を継承するクラス C を作成するには、クラス定義の際に以下のようにすれば良い。
class C( A, B ):


この時、C のインスタンスは、C -> A -> B の順にメソッドを探す。
( class C( B, A ): となっていれば、C -> B -> A の順 )
例えば、以下のように

クラス C でメソッド met1 を、
クラス A でメソッド met2, met3 を、
クラス B でメソッド met3 を実装した場合、
simple


クラス C のインスタンス ins_C では、
  ins_C.met1() -> クラス C で実装された met1 を実行
  ins_C.met2() -> クラス A で実装された met2 を実行
  ins_C.met3() -> クラス A で実装された met3 を実行
する。
(クラス B よりクラス A を先に探すので、クラス B の met3 は実行されない。)

また、メソッドの検索は再帰的に行われる。
以下のように、
class D( B, C ): と実装した場合、
recursive

D のインスタンスは始めに D -> B の順で method を探す。
そして、B を探す際に再帰的に A も探す。
A にも無い場合、B にはないと判断し、次の C を探す。
結果として、D -> B -> A -> C の順で探す。
D のインスタンスで met1 を実行すると、A で実装されたメソッドが実行される。

以上をまとめると、検索は以下の優先順位で行われる。
  1.自分自身
  2.上のクラス(上のクラスが複数有るばあい、その中の最も左の物)
  3.右のクラス(右のクラスが複数有るばあい、その中の最も左の物)

では、菱形の場合、どうなるだろう。
以下のような場合、
diamond

Python の古いバージョンでは、上記の規則に乗っ取り
D のインスタンスは D -> B -> A -> C の順にメソッドを探す。
つまり、A の met1 を C でオーバーライトしたにも関らず、C を継承している D で met1 を
実行した際に A の met1 が実行されてしまう。

しかし、Python 2.3 以降では新スタイルのクラスを定義できるようになった。
新スタイルクラスは、object というクラスを継承することで適用される。
そして、上記のクラスを新スタイルクラスで実装すると、
D のインスタンスは D -> B -> C -> A の順にメソッドを検索する。

新スタイルクラスでは、検索規則の 4番目に但書が加わるようだ。
  1.自分自身
  2.上のクラス(上のクラスが複数有るばあい、その中の最も左の物)
  3.右のクラス(右のクラスが複数有るばあい、その中の最も左の物)
  4.ただし、そのクラスが、後で検索に再度 hit する場合は後回しにする

つまり、検索規則の 1-3 のみを馬鹿正直に適用場合、D のインスタンスの検索順序は以下になる。
D -> B -> A -> C -> A
A が 2 回出てくるが、規則 4 により最後に hit した物のみ有効にする。
つまり、D -> B -> C -> A
の順になる。

この方法だと、D で met1 を実行した際に、C でオーバーライトした物を使用できる。

と、言うことを、時間をかけて実験しながら推測したが、ググったら同じことが書いてあった。
Python 2.6.4 documentation
Python 2.3 Method Resolution Order