初めてのPython(26章後編)

スタティックメソッドとクラスメソッド

2.2でstaticmethod, classmethodというビルドインオブジェクトが追加され、
呼び出しにインスタンスを必要としないスタティックメソッド、クラスメソッドが定義できる。
定義可能なメソッドは以下の3種類

  1. インスタンスメソッド
  2. スタティックメソッド
  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

Pythonインタプリタが@decoFを解釈した段階で、decoF関数の内容の解釈が始まる。