LoginSignup
1
1

More than 3 years have passed since last update.

Pythonの3大ビルトインデコレータ

Last updated at Posted at 2021-04-03

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

参考

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1