《12》クラスに頼らない OOP(6)〈Python 3.0 版〉
《Previous| |Next》
Python à la carte《記事一覧》
《12》クラスに頼らない OOP(6)
関連記事
- C言語で始める OOP, 1988, 1994.
- 実録《14》クラス(0)要求仕様《Python3.1》 - 続・ひよ子のきもち〈Python 3.0 版〉
関数:高階関数として
高階関数〔higher-order function〕は、関数を引数/リターン値にできるので、その特徴を利用して実現します。
def push(self): def push_(item): self.items.append(item) return push_ def pop(self): def pop_(): try: return self.items.pop() except: print("pop from empty stack") return pop_
関数 push/pop を定義するときに、仮引数 self を利用します。この self は、メソッド呼び出しに呼応するインスタンスそのものです。すると、この self を束縛した関数 push_/pop_ を、それぞれのリターン値に指定できます。
def Stack(): class Spam: pass self = Spam(); del Spam self.items = [] self.push = push(self) self.pop = pop (self) return self
局所変数 self は、メソッド呼び出しに呼応するインスタンスを保持します。インスタンス属性 .push/.pop を設定するときには、メソッド呼び出し push/pop の実引数に self を指定します。すると、メソッド関数 .push/.pop を呼び出したときに、この self を介して、各インスタンスが保持する情報(データ)を操作できます。
《Note》同じ操作(アルゴリズム)を共有するとともに、メソッド呼び出しに呼応する各インスタンス(オブジェクト)を介して、固有の情報(データ)を適切に管理します。■
関数:クロージャーとして
クロージャー〔closure〕は、引数以外の変数を(実行時の環境ではなく)関数を定義した環境で解決するので、その特徴を利用して実現します。
def Stack(): # class Stack(object): class Spam: pass self = Spam(); del Spam def push(item): self.items.append(item) def pop(): try: return self.items.pop() except: print("pop from empty stack") self.items = [] self.push = push self.pop = pop return self
局所変数 self は、メソッド呼び出しに呼応するインスタンスを保持します。その値は、関数 Stack を定義した環境で解決するので、関数 push/pop の本体を定義するときに self を利用できます。すると、メソッド関数 .push/.pop を呼び出したときに、この self を介して、各インスタンスが保持する情報(データ)を操作できます。
《Note》同じ操作(アルゴリズム)を共有するとともに、メソッド呼び出しに呼応する各インスタンス(オブジェクト)を介して、固有の情報(データ)を適切に管理します。■
def XStack(): # class XStack(Stack): self = Stack() def top(): if self.items: return self.items[-1] return None self.top = top return self
関数 XStack は、既存の Stack を拡張して、新たな機能 top を追加します。このように(クラスを模した)関数 Stack/XStack は、クラスを使って実現した Stack と良く似ているのが分かります。
クラス:関数 vs. 束縛されたメソッド
最後に、クラス版 Stack との違いを比較して、クラスに頼らない OOP の理解を深めます。
>>> Stack, hex(id(Stack)) (, '0x423ff0')
クラス Stack は「クラス」オブジェクトとして、固有の識別情報 0x423ff0 を持ちます。
メソッド pop は「関数」オブジェクトとして、固有の識別情報 0xff4f8 を持ちます。これは後に、複数のインスタンスから共有されます。 >>> s1 = Stack(); s1 <__main__.Stack object at 0xfddb0> >>> s2 = Stack(); s2 <__main__.Stack object at 0xfdd10>s1/s2 は、異なる「インスタンス」オブジェクトとして、それぞれ固有の識別情報 0xfddb0/0xfdd10 を持ちます。<bound method Stack.pop of <__main__.Stack object at 0xfddb0>> <bound method Stack.pop of <__main__.Stack object at 0xfdd10>>s1.pop/s2.pop は「メソッド」オブジェクトとして、各インスタンス s1/s2 に束縛されます。>>> hex(id(s1.pop)); hex(id(s2.pop)) '0xdcad0' '0xdcbc0'メソッド s1.pop/s2.pop は、同じ関数 Stack.pop を共有するとともに、異なるインスタンス s1/s2 に束縛されるので、それぞれ固有の識別情報 0xdcad0/0xdcbc0 を持ちます。