1. そもそもプロパティとは?
プロパティとは、「関数を、変数のように読み書きできる仕組み」です。
通常の関数呼び出し | プロパティを使うと |
---|---|
john.get_age() |
john.age |
john.set_age(30) |
john.age = 30 |
「関数を呼んでいる」ことを隠して、変数のように見せるのがプロパティの役割です。
2. property()を使う古い書き方
例)ageプロパティを作る
class MyClass:
def __init__(self, name, age):
self.name = name
self._age = age # 実データ
def get_age(self):
return self._age
def set_age(self, value):
self._age = value
age = property(get_age, set_age) # ここでまとめる
-
age = property(get_age, set_age)
がポイント -
john.age
でget_age()
が呼ばれる -
john.age = 30
でset_age()
が呼ばれる
3. @propertyを使う今風の書き方
例)ageプロパティを作る
class MyClass:
def __init__(self, name, age):
self.name = name
self._age = age
@property
def age(self):
return self._age
@age.setter
def age(self, value):
self._age = value
- getterには
@property
をつける - setterには
@age.setter
をつける -
property()
でまとめる必要がなく、すっきりシンプル
4. 関数名がプロパティ名になる理由
重要ポイント
@property
では、関数名=プロパティ名になります。
関数名 | プロパティ名 | アクセス方法 |
---|---|---|
age | age | john.age |
height | height | john.height |
- 関数名が
age
だからjohn.age
になる - 関数名が
height
ならjohn.height
になる
つまり
「プロパティ名=関数名」になるのが@propertyのルールです。
5. 無限ループが起きる原因
NG例)無限ループパターン
class MyClass:
def __init__(self, name, age):
self.name = name
self._age = age
@property
def age(self):
return self.age # ここが間違い!
@age.setter
def age(self, value):
self.age = value # ここも間違い!
処理 | 説明 |
---|---|
john.age |
getterが呼ばれる |
getterの中でself.age を見る |
またgetterが呼ばれる |
またself.age を見る |
無限ループ! |
setterでも同じことが起きる
@age.setter
def age(self, value):
self.age = value # setterを再帰的に呼んでしまう
6. 無限ループを防ぐ方法
プロパティではなく、直接本体(_age)を操作するのが正解です。
class MyClass:
def __init__(self, name, age):
self.name = name
self._age = age # 実データ
@property
def age(self):
return self._age # ←ここ重要!
@age.setter
def age(self, value):
self._age = value # ←ここも重要!
アクセス対象 | 説明 |
---|---|
self.age |
getter/setterが呼ばれる |
self._age |
ただのデータ(安全) |
イメージまとめ
john.age = 30 # setterが呼ばれる
↓
self._age = 30 # 本体に直接アクセス
↓
john.age # getterが呼ばれる
↓
return self._age # 本体を返す
プロパティを自分で呼ばないから無限ループを回避!
7. まとめ
やりたいこと | 正しい書き方 | NGパターン |
---|---|---|
getter | return self._age |
return self.age |
setter | self._age = value |
self.age = value |
書き方 | 説明 |
---|---|
property() |
getter・setterをまとめる古い方法 |
@property |
今風のスマートな書き方 |
まとめの一言
getter・setterの中では、プロパティではなく直接データ(self._age)を触る
これが無限ループを防ぐ鉄則です!