Java.use(better, Python)《7》継承に警鐘を鳴らす(その漆)

記事一覧《こちらに移動中です》2006年6月13日 (火)

Java.use(better, Python)  # Stairway to Real Agile World

《7》継承に警鐘を鳴らす(その漆)《Jython2.5.0》

《著》後藤いるか・伊藤うさぎ・小粒ちゃん+∞《監修》小泉ひよ子とタマゴ倶楽部
第1版♪2003/05/23

■ 概要

継承の概念を実現するのに、いくつかの方法があります。そのひとつが、新しいクラスを定義するときに(2b)親子関係にないクラスのメソッドを再利用するというものです。

継承には、
 (1)構造継承
 (2)機能継承
 (3)プロトコル継承
があって、さらに(2)機能継承は、次の3つに分類されます。
 (2a)親子関係にあるクラス間の継承
 (2b)親子関係にないクラス間の継承
 (2c)クラスとインスタンス間の継承
ともすると、Java/C# などでは、狭義の(2a)に関心が寄せられがちです。しかし、純粋な OOP の世界では、その限りではありません。では、広義の継承は、どのように実現するのでしょうか。

■ 関連記事
  •  


前の記事次の記事

《7》継承に警鐘を鳴らす(その漆)

新しいクラスを定義するときに、親子関係にないクラスのメソッドを再利用することには、どのような意味があるのでしょうか。

#                                     Jython
class Delegate:
  def __init__(self,delegate):
    self.delegate = delegate
  def __getattr__(self,name):
    return getattr(self.delegate,name)

クラス Delegate では、特殊なメソッド __init__ および __getattr__ を再定義しています。それぞれ、コンストラクター呼び出し、未定義メソッドの呼び出しに対処します。組み込み関数 getattr からは、オブジェクトの属性値が得られます。指定した文字列が、オブジェクトの属性名と一致するなら、その属性の値が得られます。

《Note》特殊メソッド:__init__
  __init__(self[, ...])

インスタンスを生成したときに呼び出されます。コンストラクターを呼び出したときの実引数が、それぞれの仮引数と対応します。このメソッドが値を返すと、実行時に例外 TypeError を生じます。□

《Note》オブジェクトメソッド:__getattr__
  __getattr__(self, name)

属性を検索しようとして、インスタンス属性、およびクラス階層を探しても見つからないときに、呼び出されます。name は、属性名です。属性の値を返すか、例外 AttributeError を生じます。□

《Note》組み込み関数:getattr
  getattr(object, name[, default])

object の属性 name の値が得られます。name は、文字列に限ります。その文字列が、object の属性名と一致するなら、その属性の値が得られます。たとえば、getattr(x, 'foo') は、x.foo と同等です。その属性名がないと、与えられた default が得られます。そうでなければ、例外 AttributeError を生じます。□

#                                     Jython
m5 = Delegate(m1)
m5.hello()
# -------------------------------- Output --
hello, world

式 m5.hello() を評価すると、変数 m1 が束縛するオブジェクトのクラス MyObject で定義されたメソッド hello を呼び出します。すると、文字列 hello, world が出力されます。

#                                     Jython
assert m5.hello == m1.hello

式 m5.hello を参照すると、m1.hello と同じ、クラス MyObject のインスタンスに束縛された`メソッド`が得られることが分ります。

#                                     Jython
assert m5.delegate == m1

変数 m5 が束縛するオブジェクトのインスタンス辞書の中から、キー属性 delegate を参照すると、その値として、変数 m1 が束縛するオブジェクトと同じものが得られることが分ります。式 m5.hello を評価するときに、getattr(m5.delegate, 'hello') は、m1.hello と同等になります。

式 m5.hello を評価するとき、変数 m5 が束縛するオブジェクトには、インスタンス属性 hello が見つかりません。次に、クラス階層を遡って、Delegate のクラス属性を探しても、やはり見つかりません。そこで、再定義された __getattr__ が呼び出されます。
メソッド __getattr__ の定義を見ると、インスタンス属性 self.delegate をキーとする値として、変数 m1 が束縛するオブジェクトが得られます。このオブジェクトの属性名に、hello と一致するものがあるなら、その属性の値をリターンオブジェクトとします。
変数 m1 が束縛するオブジェクトのインスタンス辞書には、hello と一致するものがありません。次に、MyObject のクラス辞書を探すと、そこには、キー項目 hello に対する値として、関数オブジェクトが得られます。

《Note》文:pass
  pass

空文を表します。この文を実行しても何も起こりません。構文として、文が必要となる箇所で、何も実行したくないときに記述します。□

==================================
後藤いるか+伊藤うさぎ 著 ◆ 監修:小泉ひよ子とタマゴ倶楽部

更新♪2009/08/02