Pythonの「@staticmethod」はどのように役立つのか
Peterbe.com - Newfound love of @staticmethod in Python
http://www.peterbe.com/plog/newfound-love-of-staticmethod
Pythonのデコレータ「@staticmethod」はどのように役立つのか、かんたんな例で解説している。
class Printer(object):
def __init__(self, text):
self.text = text
@staticmethod
def newlines(s):
return s.replace('\n','\r')
def printer(self):
return self.newlines(self.text)
p = Printer('\n\r')
assert p.printer() == '\r\r'
ここで「@staticmethod」がついている、メソッド「newlines」がstaticmethod。Pythonの場合、メソッドの最初の引数は通常「self」(このクラスのインスタンスを示す)だが、staticmethodではこれがない。つまり、クラスの中で定義するけれども、インスタンスとはやりとりしないのがstaticmethodだ。
インスタンスとやりとりしないのなら、メソッドでなく、ただの関数でいいのではないか。
def newlines(s):
return s.replace('\n','\r')
class Printer(object):
def __init__(self, text):
self.text = text
def printer(self):
return newlines(self.text)
p = Printer('\n\r')
assert p.printer() == '\r\r'
こんなふうに、「newlines」をただの関数にすれば十分ではないのか。もちろん、これでもいい。多くの場合、これで足りる。
ではなぜ、staticmethodなるものがあるのか。staticmethodは、「ただの関数」を通常のモジュールレベルではなく、クラスレベルで定義したものと言える。「ただの関数」をクラスレベルで定義して、なんの意味があるのかというと、例えばこれを継承して、サブクラスでオーバーライドできる。
class UNIXPrinter(Printer):
@staticmethod
def newlines(s):
return s.replace('\n\r', '\n')
p = UNIXPrinter('\n\r')
assert p.printer() == '\n'
これと同じことを、モジュールレベルの「ただの関数」でやろうとすると、なかなかできない。
このようにサブクラスでオーバーライドしたい場合、通常は、ただのメソッド(最初の引数がself)を使うだろう。もちろんそれでもいい。しかし、そのメソッドがインスタンスとやりとりしないのであれば、「@staticmethod」のほうが、そのメソッドの意味・役割がより明確になる。
ちなみに、ブログ主のPeter Bengtssonは、いまはMozillaで働いているPythonエンジニアで、以前はZopeをやっていた。古いZopeユーザなら「QuickLinks」というプロダクトを覚えているかもしれないが、その作者である。
関連エントリ:
Pythonで関数プログラミング入門
http://mojix.org/2009/04/26/python_functional
Pythonを使って、1行でファイル共有Webサーバを立ち上げる
http://mojix.org/2009/03/05/python_one_line_fileserver
http://www.peterbe.com/plog/newfound-love-of-staticmethod
Pythonのデコレータ「@staticmethod」はどのように役立つのか、かんたんな例で解説している。
class Printer(object):
def __init__(self, text):
self.text = text
@staticmethod
def newlines(s):
return s.replace('\n','\r')
def printer(self):
return self.newlines(self.text)
p = Printer('\n\r')
assert p.printer() == '\r\r'
ここで「@staticmethod」がついている、メソッド「newlines」がstaticmethod。Pythonの場合、メソッドの最初の引数は通常「self」(このクラスのインスタンスを示す)だが、staticmethodではこれがない。つまり、クラスの中で定義するけれども、インスタンスとはやりとりしないのがstaticmethodだ。
インスタンスとやりとりしないのなら、メソッドでなく、ただの関数でいいのではないか。
def newlines(s):
return s.replace('\n','\r')
class Printer(object):
def __init__(self, text):
self.text = text
def printer(self):
return newlines(self.text)
p = Printer('\n\r')
assert p.printer() == '\r\r'
こんなふうに、「newlines」をただの関数にすれば十分ではないのか。もちろん、これでもいい。多くの場合、これで足りる。
ではなぜ、staticmethodなるものがあるのか。staticmethodは、「ただの関数」を通常のモジュールレベルではなく、クラスレベルで定義したものと言える。「ただの関数」をクラスレベルで定義して、なんの意味があるのかというと、例えばこれを継承して、サブクラスでオーバーライドできる。
class UNIXPrinter(Printer):
@staticmethod
def newlines(s):
return s.replace('\n\r', '\n')
p = UNIXPrinter('\n\r')
assert p.printer() == '\n'
これと同じことを、モジュールレベルの「ただの関数」でやろうとすると、なかなかできない。
このようにサブクラスでオーバーライドしたい場合、通常は、ただのメソッド(最初の引数がself)を使うだろう。もちろんそれでもいい。しかし、そのメソッドがインスタンスとやりとりしないのであれば、「@staticmethod」のほうが、そのメソッドの意味・役割がより明確になる。
ちなみに、ブログ主のPeter Bengtssonは、いまはMozillaで働いているPythonエンジニアで、以前はZopeをやっていた。古いZopeユーザなら「QuickLinks」というプロダクトを覚えているかもしれないが、その作者である。
関連エントリ:
Pythonで関数プログラミング入門
http://mojix.org/2009/04/26/python_functional
Pythonを使って、1行でファイル共有Webサーバを立ち上げる
http://mojix.org/2009/03/05/python_one_line_fileserver