《09》クラスに頼らない OOP(3)〈Python 3.0 版〉

Previous| |Next
Python à la carte記事一覧
《09》クラスに頼らない OOP(3)

《著》小粒ちゃん《監修》小泉ひよ子とタマゴ倶楽部
第1版♪2003/05/25 ● 第2版♪2004/06/01 ● 第3版♪2009/02/28

関連記事

複数のインスタンスオブジェクト

クラスに頼らない環境下でも「同じ特性を持つオブジェクトが、それぞれに異なる状態になり得るか」を確認する必要があります。

def ex3():
    stack1 = Stack()
    stack1.name = "stack1"    # dispensable
    stack2 = Stack()
    stack2.name = "stack2"    # dispensable
    for e1,e2 in zip(range(3),"ABC"):
        stack1.push(e1)       ;print(stack1.name,stack1)
        stack2.push(e2)       ;print(stack2.name,stack2)

同じ特性を持つ2つのスタック stack1/stack2 を用意するとともに、属性 .name には区別するために名前を設定します。一方の stack1 には整数だけを積み、他方の stack2 には文字列だけを積みます。すると、次のように、

>>> ex3()
stack1 [0]
stack2 ['A']
stack1 [0, 1]
stack2 ['A', 'B']
stack1 [0, 1, 2]
stack2 ['A', 'B', 'C']

それぞれが異なる状態を維持できるのが分かります。また、2つの異なるスタックに共通する特性として、どちらにも同じメソッド関数 push を適用できるのが分かります。


機能の拡張(クラス継承に代わるもの)

クラスに期待される役割のひとつに「継承」があります。そこで、クラスに頼らない環境下でも「機能を継承するとともに、その機能を拡張できるか」を確認する必要があります。そこで、

def top(self):
    if self.items:
        return self.items[-1]
    return None

既存のインスタンスオブジェクトにはない関数 top を、新たな機能として拡張(追加)します。

def ex4():
    stack = Stack()
    stack.top = lambda: top(stack)
    s = stack.top()     ;print(stack,s)
    stack.push("A")     ;print(stack)
    s = stack.top()     ;print(stack,s)
    stack.push("B")     ;print(stack)
    s = stack.top()     ;print(stack,s)

インスタンス属性 .top に(クロージャーとしての)lambda 関数を設定します。stack の値は、lambda 関数を定義するときに解決するので、インスタンスに固有の関数(メソッド)になります。そのため、メソッド呼び出しと同じ記法 stack.top() などが使えます。すると、次のように、

>>> ex4()
[] None
['A']
['A'] A
['A', 'B']
['A', 'B'] B

スタックに拡張したメソッド関数 top を適用したときに、空のときには None が得られ、それ以外はスタックの最上位にある値を参照できるのが分かります。


機能の変更(クラス継承に代わるもの)

クラス継承に伴う機能拡張には、新たな機能を追加するだけでなく「既存の機能を変更できるか」を確認する必要があります。そこで、

import sys
def push_int(self, item):
    if isinstance(item,int):
        self.items.append(item)
    else:
        print("stack expected 'int' item, got {0!r}".format(item),file=sys.stderr)

既存のインスタンスオブジェクトに適用できる関数 push の機能を変更して、スタックに整数以外を積めないようにします。

def ex5():
    stack = Stack()     ;print(stack)
    stack.push = lambda item: push_int(stack,item)
    stack.push(1)       ;print(stack)
    stack.push("2")     ;print(stack)
    stack.push(2)       ;print(stack)

インスタンス属性 .push に、lambda 関数を再設定します。すると、次のように、

>>> ex5()
[]
[1]
stack expected 'int' item, got '2'
[1]
[1, 2]

スタックには、整数 2 を積めても、文字列 '2' は積めなくなったのが分かります。

Tips

クラス継承に伴う支援(新たな機能の追加、既存の機能の変更)も、クラスに頼らずに実現できるようになります。

Last updated♪09/03/24