今の世の中、オブジェクト指向プログラミングは当たり前だ。
しかし、じゃ「メタクラスは?」と聞かれて即答できる人は、ある程度の勉強家だろう。
なぜか……昨今の「オブジェクト指向プログラミング言語」の主流格であるC++にもJavaにも、メタクラスは存在しないからだ。
>>> X = type('X',(),{})
>>> x = X()
>>> X
<class '__main__.X'>
>>> x
<__main__.X object at 0x00C171F0>
メタクラスを弄るには、typeオブジェクトを使用する。
type('クラス名',(スーパークラスのタプル),{属性の辞書})
属性は即ち、フィールド(スロット)やメソッドである。
>>> C = type('C',(),{'x':666, 'y':lambda self:print('Hello')})
>>> c = C()
>>> c.x
666
>>> c.y()
Hello
>>>
もう、勘のいい人は気づいたと思うが、グローバル空間に名前を残さずに、無名関数ならぬ無名クラスを作成することも可能である。
>>> n = type('',(),{})()
>>> n
<__main__. object at 0x00C171F0>
>>>
コンテナとしてしか使わないオブジェクトにわざわざクラスを作るのが面倒、という人には便利かもしれない(空白カッコの行列が不気味、という方にはお勧めしかねるが)>>> class M(type):pass ... >>> class oldC: ... __metaclass__ = M ...Python 3000からは、以下のように書ける。
>>> class newC(metaclass = M): ... pass ...とりあえず、簡単な例として、型判別した時にclassオブジェクトでなく、オリジナルの表示ができるよう、__repr__属性を変更してみよう。
>>> 666 666 >>> 'Hello' 'Hello' >>> class C0:pass ... >>> c0 = C0() >>> c0 <__main__.C0 object at 0x00C269D0> >>>この表現方法は、そのオブジェクトのクラスの__repr__属性によって決定される。
>>> class C1: ... def __repr__(self): ... return "C1's Object!" ... >>> c1 = C1() >>> c1 C1's Object! >>>オブジェクトの文字表現はコレで十分なのだが、typeで「型(クラス)」を表示させると、以下のようになってしまう。
>>> type(666)
<type 'int'>
>>> type('Hello')
<type 'str'>
>>> type(c0)
<class '__main__.C0'>
>>> type(c1)
<class '__main__.C1'>
c0もc1も「クラスオブジェクト」として、ひっくくられてしまう。>>> class M(type): ... def __repr__(cls): ... return "<type '" + cls.__name__ + "'>" ... >>> class C2(metaclass = M): ... __name__ = 'C2' ... def __repr__(self): ... return "C2's Object!" ... >>> c2 = C2() >>> c2 C2's Object! >>> type(c2) <type 'C2'> >>>Pythonはオブジェクト自身の名前を参照するのが異様に困難(かつ、その方法は不確定)なので、__name__という名札をつけてやる必要があるが、とりあえずコレで型を調べるとクラスの名前が表示されるようにはなる。