初めてのPython(26章後編)
スタティックメソッドとクラスメソッド
2.2でstaticmethod, classmethodというビルドインオブジェクトが追加され、
呼び出しにインスタンスを必要としないスタティックメソッド、クラスメソッドが定義できる。
定義可能なメソッドは以下の3種類
- インスタンスメソッド
- スタティックメソッド
- クラスメソッド
スタティックメソッド
第一引数にインスタンスが渡されないメソッド。
クラスを使って呼び出すことも出来るし、インスタンスを使って呼び出すことも出来る。
下の例のs_methodが該当
[kobakoba0723@fedora13-intel64 ~]$ cat static_method.py #!/usr/bin/env python class C1(object): def method(self, x): print 'a instance method of', self.__class__ print 'x:', x def s_method(x): print 'a static method of C1' print x s_method = staticmethod(s_method) if __name__ == '__main__': C1().method(10) C1.s_method(10) C1().s_method(10) [kobakoba0723@fedora13-intel64 ~]$ python static_method.py a instance method of <class '__main__.C1'> x: 10 a static method of C1 10 a static method of C1 10
クラスメソッド
第一引数にインスタンスでなくクラスが渡されるメソッド。
クラスを使って呼び出すことも出来るし、インスタンスを使って呼び出すことも出来る。
下の例のc_methodが該当
[kobakoba0723@fedora13-intel64 ~]$ cat class_method.py #!/usr/bin/env python class C1(object): def method(self, x): print 'a instance method of', self.__class__ print 'x:', x def c_method(cls, x): print 'a class method of', cls.__name__ print 'x:', x c_method = classmethod(c_method) class C2(C1): pass if __name__ == '__main__': C1().method(10) C1.c_method(10) C1().c_method(10) C2.c_method(10) C2().c_method(10) [kobakoba0723@fedora13-intel64 ~]$ python class_method.py a instance method of <class '__main__.C1'> x: 10 a class method of C1 x: 10 a class method of C1 x: 10 a class method of C2 x: 10 a class method of C2 x: 10 [kobakoba0723@fedora13-intel64 ~]$
クラスメソッドの場合、第一引数にクラス名が渡されるので呼び出し元のクラスに応じたことが出来るが、
スタティックメソッドの場合、固定のことしか出来ない。
関数デコレータ
関数デコレータを使うと、スタティックメソッド/クラスメソッドは以下のように書ける
class C1(object): def method(self, x): print 'a instance method of', self.__class__ print 'x:', x @staticmethod def s_method(x): print 'a static method of C1' print x @classmethod def c_method(cls, x): print 'a class method of', cls.__name__ print 'x:', x
@staticmethod が s_method=staticmethod(s_method), @classmethod が c_method=classmethod(c_method)と同じことを実現している。
@staticmethod/classmethodでs_methodやc_methodに機能を追加(修飾)している。
@hoge def piyo(): pass ↑は ↓のシンタックスシュガー def piyo(): pass piyo = hoge(piyo)
デコレータとして使えるのは、staticmethod/classmethodだけでなく、
クラスや関数を自分で定義してデコレータとして使える。
例えば、以下のようにdecoFというデコレータを定義してデコレートすることが出来る。
#!/usr/bin/env python def decoF(func): print 'type(func):', type(func) print "Now in decoF():", func return "string returned by decoF()" @decoF def testF(value): print "Now in testF():", value print "----------" print 'type(testF):', type(testF) print testF
これを実行すると、
[kobakoba0723@fedora13-intel64 decorator]$ python deco1.py type(func): <type 'function'> Now in decoF(): <function testF at 0x7f3baf297848> ---------- type(testF): <type 'str'> string returned by decoF() [kobakoba0723@fedora13-intel64 decorator]$
print testFに該当する箇所で、decoFの復帰値"string returned by decoF()"が出力されている。
デコレータを使うことで、testFという変数の中身を関数から文字列に置き換えている。
また、出力を見ると、decoFのprint出力が行われ、その後メイン(?)のprint文が実行されている。
デコレータは、デコレートした関数の実行時じゃなくて、関数の定義時に実行される。
Pythonのデバッガで処理の流れを追ってみるとそれがよくわかる。
[kobakoba0723@fedora13-intel64 decorator]$ python -m pdb deco1.py > /home/kobakoba0723/decorator/deco1.py(3)<module>() -> def decoF(func): (Pdb) s > /home/kobakoba0723/decorator/deco1.py(8)<module>() -> @decoF (Pdb) --Call-- > /home/kobakoba0723/decorator/deco1.py(3)decoF() -> def decoF(func): (Pdb) > /home/kobakoba0723/decorator/deco1.py(4)decoF() -> print 'type(func):', type(func) (Pdb) type(func): <type 'function'> > /home/kobakoba0723/decorator/deco1.py(5)decoF() -> print "Now in decoF():", func (Pdb) Now in decoF(): <function testF at 0x2006ed8> > /home/kobakoba0723/decorator/deco1.py(6)decoF() -> return "string returned by decoF()" (Pdb) --Return-- > /home/kobakoba0723/decorator/deco1.py(6)decoF()->'string returned by decoF()' -> return "string returned by decoF()" (Pdb) > /home/kobakoba0723/decorator/deco1.py(12)<module>() -> print "----------" (Pdb) ---------- > /home/kobakoba0723/decorator/deco1.py(13)<module>() -> print 'type(testF):', type(testF) (Pdb) type(testF): <type 'str'> > /home/kobakoba0723/decorator/deco1.py(14)<module>() -> print testF (Pdb) string returned by decoF() --Return-- > /home/kobakoba0723/decorator/deco1.py(14)<module>()->None -> print testF (Pdb) --Return-- > <string>(1)<module>()->None (Pdb) The program finished and will be restarted