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

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

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

関連記事

実現:関数を使って(非 OOP 版)

def Stack():    # non OOP
    self = Spam()
    self.items = []
    return self

関数 Stack は、クラス呼び出しを模したものです。名前を大文字で始めたのも「意図的に」クラス呼び出しと混乱させるためです。(これを利用する)コードの断片を見ただけでは「関数かクラスか」を区別できませんし、それを区別する必要もないのです。

《Note》ここで、Spam() とあるのは、インスタンス(オブジェクト)self を生成するのに利用しただけで、それ以外の目的で、クラス(オブジェクト)Spam は必要としません。ここで、クラス呼び出し Spam() ではなく、object() にするとどうなるか、試してみるのも一興です。■

■ オブジェクト:存在の耐えられない軽さ

クラス Spam は(存在するだけで)なにもしないオブジェクトを生成するために利用します。

class Spam(object): pass

この記事のタイトルに「クラスに頼らない OOP」としておきながら、ここでクラスが登場するのは「変」かもしれません。その存在意義は、メソッド呼び出し(ドット「.」を使う)を模した表記をするための、便宜的なものです。

《Note》実際には(説明の都合から)オブジェクトの状態を出力して確認するため、次のように、

class Spam(object):
    def __repr__(self): return self.__repr()    # dispensable
    pass

メソッド __repr__ を用意しました。ただし、ここで指摘したい問題の「本質」には影響しません。■

■ メソッドをそのまま関数にすると…

次に示す関数は、例題(非 OOP 版/擬 OOP 版)で共通して利用します。

def push(self, item):
    self.items.append(item)    
def pop(self):
    try:
        return self.items.pop()
    except:
        print("{0}:".format(self.__name__),
            "pop from empty stack")

push/pop は、関連する〈記事〉から抜粋したものです。実際に、クラスの本体から「メソッド」だけを抽出して、インデントを浅くしただけの「関数」です。

実現:関数を使って(擬 OOP 版)

def Stack():    # pseudo OOP
    self = Spam()
    self.__name__ = "Stack"                        # dispensable
    self._Spam__repr = lambda: repr(self.items)    # dispensable

    self.items = []
    self.push = lambda item: push(self,item)
    self.pop  = lambda     : pop (self)
    return self

OOP 版との違いは、インスタンス属性 .push/.pop に(クロージャーとしての)lambda 関数を設定していることです。self の値は、lambda 関数を定義するときに解決するので、インスタンスに固有の関数(メソッド)になります。そのため、メソッド呼び出しと同じ記法が使えます。すると、

    stack = Stack()

は、クラス呼び出しによって、インスタンスを生成するのと同等の表現になり、

    stack.push("A")
    stack.pop()

は、メソッド呼び出しによって、オブジェクトを操作するのと同等の表現になります。

受講者への課題

インスタンスを生成した後で、クラスを削除するとどうなるか、

    global Spam         ;print(Spam)
    stack = Stack()
    del Spam
    stack.push("A")     ;print(stack)
    stack.push("B")     ;print(stack)
    stack.push("C")     ;print(stack)
    s = stack.pop()     ;print(stack,s)
    s = stack.pop()     ;print(stack,s)
    s = stack.pop()     ;print(stack,s)
    s = stack.pop()     ;print(stack,s)
    pass		;print(Spam)

この動作を確認するとともに、その理由について考察してください。■

Tips

インスタンスオブジェクトは(クラスオブジェクトを介さずに)自分で処理できるようになります。

Last updated♪09/03/23