Address
304 North Cardinal St.
Dorchester Center, MA 02124

Work Hours
Monday to Friday: 7AM - 7PM
Weekend: 10AM - 5PM

【Python入門】@propertyについてその基本とメリットをわかりやすく解説

Pythonのproperty()と@propertyデコレータについてその基本をわかりやすく解説

Pythonにはデコレータというものがありますが、その中でもともと標準で用意されているデコレータとして次の3つが有名です。

  • スタティックメソッド(@staticmethod)
  • クラスメソッド(@classmethod)
  • プロパティ(@property)

今回はこのプロパティ(@property)について、その基本的な考え方と使い方、そして使い場合のメリットについて解説します。

@propertyと、その使い方

結論:@propertyとは?

@propertyとはクラス内部で定義されたメソッドを、属性として使えるようにするデコレータの1種です。

Pythonのデコレータについてはこれまでいくつかの解説記事を書きました。たとえば次の3つの記事をご覧ください。

これだけでは当然よくわからないので、@propertyなしの普通のクラスを使う場合と、@propertyありのクラスを使う場合との違いを見ていきましょう。

@properyなしの普通のクラスの使い方

class C_1:
   def __init__(self, name: str):
       self.name = name
       
   def  print_name(self):
       print(self.name)

c_1 = C_1("Tom")

# インスタンスの属性nameを取得
c_1.name  # ==> 'Tom'

# インスタンスのメソッドprint_nameを実行
c_1.print_name()  # ==> Tom

普通クラスを使う場合は、そのインスタンスの属性の情報を取得するときは、

目的 記述方法
インスタンスの属性の情報を取得 インスタンス名.属性名
インスタンスのメソッドを実行 インスタンス名.メソッド名()

このように、メソッドを実行するときは「()」をつけます。

しかし@propertyを使ったメソッドについては、「()」をつけずに記述・実行することが可能となります。つまり、属性の場合と同じ書き方ができます。そこで次に@propertyが存在するクラスの場合の使い方を見ていきましょう。

@propertyが記述されているクラスの使い方

class C_2:
   def __init__(self, name: str):
       self.name = name
       
   @property    
   def  print_name(self):
       print(self.name)

c_2 = C_2("Tom")

# インスタンスの属性nameを取得
c_2.name  # ==> 'Tom'

# @propertyを使ったメソッドを実行:「()」が不要
c_2.print_name  # ==> Tom

上述のように、

c_2.print_name

の部分の書き方に注意してください。メソッドのはずなのに、「()」がありません。それでもきちんとそのメソッドが実行されています。

ではこのような@propertyに一体どのようなメリットがあるのでしょうか。

@propertyを使うメリットについて

@propertyを使うメリットはいくつかあるでしょうが、その1つとして言えるのはまさに上で書いたように「属性の情報を取得する場合と同じ形で書ける」という点です。

これを説明するため次のコードを見てください。

class C_3():
    
    # __init__の中はメソッドを使わない純粋な代入文のみでシンプルな内容
    def __init__(self, product_name):
        self.product_name = product_name
    
    # 価格についてはこのメソッドで処理    
    @property
    def price(self):
        if self.product_name == "Nike Panda":
            return 15000
        
        else:
            return 5000
    

c_3 = C_3("Nike Panda")


c_3.product_name  # ==> 'Nike Panda'
c_3.price  # ==> 15000

このコードにおいて、クラスC_3はスニーカーという物体の情報だと思ってください。そのインスタンスであるc_3はスニーカーなので、普通は

  • 製品名
  • 価格

という2つの情報を持っているでしょう。そこで上のコードでもその2つの情報を登録しています。

そして価格については、

  • 製品名がNike Pandaならば15000円
  • そうでなければ5000円

とインスタンス生成後の初期化処理において場合分けを行っています。

この処理を、__init__メソッド内部で書いてもエラーになるわけではありません。しかし、Pythonの流儀・哲学として__init__メソッド内部の処理は、できるだけ単純な内容であることが良いとされています。極論すれば、__init__内部は上のコードのような単純でシンプルな代入文だけにしましょうということです。

したがって条件によって代入されるデータが変わるような処理は__init__内部に書かず、その外側に出してしまおうというわけです。これで__init__はシンプルな見た目となり、後でコードを読むときに見やすく、そして__init__の処理が理解しやすくなります。可読性があがります。

また価格情報については、「製品名と製品価格」という概念に対応させ、「name」「price」という単純な名詞形にしたいですね。

そこで、

  • c_3.name
  • c_3.price

という名前すると見た目の統一感が出ますし、コードの意味も素早く理解できるでしょう。

このうち「c_3.price」については、見た目は価格情報を格納している「属性」ですが、実質的には「複数の条件によって分岐させるメソッド」です。ですが@propertyを使うとメソッドであるという実質を隠して、純粋な属性であるnameと並ぶ、同種の属性であるかのように見せかけることができます。

@propertyを使うメリットの1つというのは、このように他の属性との関係で見た目の統一感を作り出し、コードの可読性や理解のしやすさを手助けするという点にあります。

@classmethodと@staticmethodについて

またクラス内部で使われるデコレータの他種であるクラスメソッド(@classmethod)とスタティックメソッド(@staticmethod)については次の記事で解説を書いていますので、ぜひご覧ください。

Pythonを最速でマスターする方法

Pythonの基礎を効率よく学習するには、やはりただ本を読むだけよりも動画による学習がわかりやすくておすすめです。

特に世界最大の動画学習サイトのUdemy(ユーデミー)では現役エンジニアによる人気講座が多数あります。その中でも人気のものを5つ紹介したのが次の記事です。