Python.use(better)《4》継承に警鐘を鳴らす(その肆)
‖記事一覧‖ Python.use(better)《Python3.1》
継承に警鐘を鳴らす(その肆)
オブジェクト指向プログラミング〔OOP〕の基本概念の理解を深めます。
※ JPython1.1/Jython2.2 で作成した例題を、Python3.1 で再構成しました。
継承に警鐘を鳴らす(その肆)
継承の概念を実現するのに、いくつかの方法があります。そのひとつが、クラスを利用するというものです。次に、親子関係にあるクラスをどのように表現するかを紹介します。
《note》図は、簡略したタプルのモデルを含みます。詳細は、以下(および関連記事)で紹介します。□
- 2006-02-05 Python.use(better) #OOP への扉を開く:コンテナー
■ 既存のクラスと親子関係を結ぶ
新しいクラスを定義するときに、既存のクラスと親子関係を結ぶ意義について考察します。
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インスタンスオブジェクトも(他のオブジェクトと同様に)属性を介して、他のオブジェクトを参照できます。ただし、インスタンスオブジェクト p2 が、インスタンス属性 happy を持つものの、特殊属性 __func__ を介さないと、関数オブジェクトは得られません。そのため、p2.happy という表現は、p2.__class__. __bases__[0].__dict__["happy"] の簡略表記(近道)と見なせます。> >>> hex(id(p2.happy)) '0x124e620' >>> hex(id(p2.happy.__func__)) '0x125e0c0' ■ 束縛メソッド
メソッド呼び出しには、実行時に確定するオブジェクト(慣例では、変数 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