Pythonのビルトイン関数のうち、デコレータは3つです。それは@staticmethod、@classmethod、@propertyです。
Built-in Functions — Python 3.9.2 documentation
ちなみにPythonの標準ライブラリに含まれるデコレータに関しては、有志の方がまとめているレポジトリがあります。
@staticmethod、 @classmethod
@staticmethodはインスタンスメソッドをスタティックメソッドに変えてくれるデコレータです。通常インスタンスメソッドは第一引数にselfが入りますが、スタティックメソッドでは第一引数にselfが入りません。
スタティックメソッドはselfにアクセスしなくてもいい場合に用います。
@classmethodはインスタンスメソッドをクラスメソッドに変えてくれるデコレータです。クラスメソッドは第一引数にクラスオブジェクトが入ります。
クラス変数や継承先のクラスの情報を使いたい場合に用います。
インスタンスメソッド、スタティックメソッド、クラスメソッドの違いの例をコードとして以下に書かせていただきました。
class C:
class_variable = "CV"
def __init__(self):
self.instance_variable = "IV"
def instance_method(self):
print("An instance method was called.")
print("instance_variable is {}".format(self.instance_variable))
@staticmethod
def static_method():
print("A static method was called.")
@classmethod
def class_method(cls):
print("A class method was called")
print("class_variable is {}".format(cls.class_variable))
実行例は以下のようになります。
instance = C()
print("=====instance method=====")
instance.instance_method()
print()
print("=====static method=====")
C.static_method()
print()
instance.static_method()
print()
print("=====class method=====")
C.class_method()
print()
instance.class_method()
実行結果は以下のようになります。
=====instance method=====
An instance method was called.
instance_variable is IV
=====static method=====
A static method was called.
A static method was called.
=====class method=====
A class method was called
class_variable is CV
A class method was called
class_variable is CV
@property
Pythonではインスタンス変数に直接アクセスできてしまいます。そのためインスタンスが望まない変数を持ってしまうことがあります。この問題に対処できるのが@propertyです。
例えばpriceというインスタンス変数は基本的に0より大きい数字であるべきです。しかしpriceが負の数であっても例外が投げられないという問題を考えることができます。
product.price = -200 # 例外を投げたい
例として以下のようなコードを書かせていただきました。
class Product:
def __init__(self, price):
self._price = price
@property
def price(self):
print("Getter is called.")
return self._price
@price.setter
def price(self, price):
print("Setter is called.")
if price < 0:
raise ValueError("price should be 0 or more than 0")
self._price = price
@price.deleter
def price(self):
print("Deleter is called.")
self._price = None
実行例は以下のようになります。
product = Product(100)
print("=====getter=====")
product.price
print()
print("=====setter=====")
product.price = 200
print()
print("=====deleter=====")
del product.price
print()
print("=====invalid argument=====")
product.price = -200
実行結果は以下のようになります。
=====getter=====
Getter is called.
=====setter=====
Setter is called.
=====deleter=====
Deleter is called.
=====invalid argument=====
Setter is called.
Traceback (most recent call last):
File "property.py", line 38, in <module>
product.price = -200
File "property.py", line 14, in price
raise ValueError("price should be 0 or more than 0")
ValueError: price should be 0 or more than 0