Python.use(better)《4》継承に警鐘を鳴らす(その肆)

記事一覧 Python.use(better)《Python3.1》

継承に警鐘を鳴らす(その肆)

《著》後藤いるか・伊藤うさぎ・小粒ちゃん+∞《監修》小泉ひよ子とタマゴ倶楽部
第1版♪1988/05/23 ● 第2版♪2001/01/29 ● 第3版♪2009/12/15

オブジェクト指向プログラミング〔OOP〕の基本概念の理解を深めます。
※ JPython1.1/Jython2.2 で作成した例題を、Python3.1 で再構成しました。


継承に警鐘を鳴らす(その肆)

継承の概念を実現するのに、いくつかの方法があります。そのひとつが、クラスを利用するというものです。次に、親子関係にあるクラスをどのように表現するかを紹介します。


《note》図は、簡略したタプルのモデルを含みます。詳細は、以下(および関連記事)で紹介します。□

■ 既存のクラスと親子関係を結ぶ

新しいクラスを定義するときに、既存のクラスと親子関係を結ぶ意義について考察します。

    class Inherit(Piyo):
        pass

クラス Inherit は、既存のクラス Piyo を親に持ち、何もメソッドを定義していません。pass は、空文に相当し、何もしないことを意味します。

■ クラスオブジェクト

クラスも「呼び出し可能オブジェクト」なので、演算子 () を利用できます。

>>> p2 = Inherit(); p2
<__main__.Inherit object at 0x135b9d0>

クラスオブジェクト Inherit に演算子 () を適用すると、新たなインスタンスオブジェクトを生成します。変数 p2 は、生成した(クラス Inherit の)インスタンスオブジェクトを束縛します。対話モードでは、式 p2 を評価すると、変数 p2 が束縛するオブジェクトに固有の識別情報が出力されます。すると、p2 は(Piyo ではなく)Inherit のインスタンスオブジェクト __main__.Inherit object で、固有の識別情報 0x135b9d0 を持つのが分かります。この識別情報は、その状況(実行環境)ごとに値が異なります。

    
Are you Happy?
式 p2.happy() を評価すると、インスタンスオブジェクト p2 が属するクラス Inherit の親クラス Piyo で定義したメソッド happy を呼び出します。すると、メソッド happy の本体に記述したコードの断片を評価して、文字列 "Are you Happy?" を出力します。
■ 特殊属性:__bases__
特殊属性 __bases__ を参照すると、その親クラスを列挙したタプルが得られます。
>>> hex(id(Inherit))
'0x4b2c00'
    
(,)
インスタンスオブジェクト p2 が属するクラス Inherit は、Piyo を親クラスに持つので、これを要素に含むタプルが得られます。図には、Inherit のクラス属性 __bases__ が、Piyo(と同じもの)を参照する様子を簡略表記しています。
    
(,)
クラス Piyo を定義するときには、親クラスを省略しましたが、これは object を指定したものと見なされます。そのため、object を要素に含むタプルが得られます。すべてのクラスが object を頂点とする子孫になるので、図では、Piyo のクラス属性 __bases__ を省略しています。
    
()
クラス object は、親クラスを持たないので、空タプル () が得られます。
演算子:in
演算子 in を利用すると、指定したキーがメソッド辞書に含まれるかが分かります。
>>> "happy" in Inherit.__dict__
False
>>> "happy" in Piyo.__dict__
True
インスタンスオブジェクト p2 が属するクラス Inherit のメソッド辞書には、キー要素 "happy" が含まれません。しかし、その親クラス Piyo のメソッド辞書には、キー要素 "happy" が含まれます。そのため、メソッド呼び出し p2.happy() に呼応する関数オブジェクトは、(クラス Inherit ではなく)クラス Piyo のメソッド辞書に帰結します。
>>> p2.happy
>
>>> hex(id(p2.happy))
'0x124e620'
>>> hex(id(p2.happy.__func__))
'0x125e0c0'
インスタンスオブジェクトも(他のオブジェクトと同様に)属性を介して、他のオブジェクトを参照できます。ただし、インスタンスオブジェクト p2 が、インスタンス属性 happy を持つものの、特殊属性 __func__ を介さないと、関数オブジェクトは得られません。そのため、p2.happy という表現は、p2.__class__. __bases__[0].__dict__["happy"] の簡略表記(近道)と見なせます。
■ 束縛メソッド
メソッド呼び出しには、実行時に確定するオブジェクト(慣例では、変数 self で参照する)の存在が不可欠です。そのため「束縛メソッド」と「非束縛メソッド」とに分類されます。
>>> p2 = Inherit()
>>> p2.happy()           #1: bound method
Are you Happy?
>>> Inherit.happy(p2)    #2: un-bound method
Are you Happy?
>>> Piyo.__dict__["happy"](p2)
Are you Happy?
>>> Inherit.__dict__["happy"](p2)
Traceback (most recent call last):
  ...
KeyError: 'happy'
>>> Inherit.__bases__[0].__dict__["happy"](p2)
Are you Happy?
束縛メソッド happy #1 は、実行時に確定するインスタンスオブジェクト p2 の他に、実引数を指定する必要はありません。しかし、未束縛メソッド happy #2 は、1つの実引数(インスタンスオブジェクト p2)を指定する必要があります。 》こちらに移動中です《TOP

関連記事

Last updated♪2010/01/13