《08》クラスに頼らない OOP(2)〈Python 3.0 版〉
《Previous| |Next》
Python à la carte《記事一覧》
《08》クラスに頼らない OOP(2)
関連記事
- C言語で始める OOP, 1988, 1994.
- 実録《14》クラス(0)要求仕様《Python3.1》 - 続・ひよ子のきもち〈Python 3.0 版〉
実現:関数を使って(非 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 版)
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)
この動作を確認するとともに、その理由について考察してください。■