TL;DR
クラスにおけるプロパティ(@property)とは、インスタンスメソッドを、外部からアクセスしたり、変更できないようにする機能である。
プロパティのポイント
- ゲッター、セッターは、非公開属性の値を読み書きする
- @で始まる文をデコレータと呼ぶ
- def 文で機能を定義する
- property と setter のインスタンスメソッド名は同じにする
- インスタンスメソッドを()を付けずに呼び出せる
- 属性にアンダースコア(
_
)をつけるとプライベート変数になる
英語において、property は「所有している性質、属性」、setter は「値を設定」などの意味があるが、Python においては次の性質がある。
@property | @インスタンスメソッド.setter |
---|---|
getter | setter |
属性アクセス(値の取得時) | 新しい値を設定する |
ゲッターメソッドの前 | セッターメソッドの前 |
class クラス名:
def __init__(self, 仮引数):
self.インスタンス変数 = 仮引数
@property
def インスタンスメソッド(self):
return self.インスタンス変数
@インスタンスメソッド.setter
def インスタンスメソッド(self, 仮引数):
self.インスタンス変数 = 仮引数
@property
次のコードは、正方形の面積を求めるものである。edge 属性を書き換えている。
class Square:
def __init__(self, edge):
self._edge = edge
@property
def calc(self):
return self._edge ** 2
square = Square(5)
square.calc
# 25
square.edge = 10
square.calc # 100
@プロパティ.setter
次のコードの @name.setter
が、セッターである。setter は値が代入されたときに呼び出される。メソッド名は、@property を付けたメソッド名をそのまま利用する必要がある。
class A:
def __init__(self, input_name):
self.hidden_name = input_name
@property # 値が呼び出されたとき
def name(self):
print('getter')
return self.hidden_name
@name.setter # 値が代入されたとき
def name(self, input_name):
print('setter')
self.hidden_name = input_name
a = A('値1')
a.name # getter 値1
a.name = '値2' # setter
a.name # getter 値2
マングリング(名前装飾)
そもそも Python には private 変数がないが、それに近いことはできる。
属性にアンダースコア(_
)をつけるとプライベート変数になる。インスタンスのユーザーには非公開にしておきたいときに使う。
アンダースコアを 2 つ(__
)つけた場合、マングリングが働く。マングリングをつかうと、インスタンス変数にアクセスできなくなる。サブクラスでの名前衝突を防ぐために使われる。
次に示すコードのように、実際に属性が非公開になるわけではないが、意図しないアクセスをある程度防ぐことができる。
class A:
def __init__(self, input_name):
self.__name = input_name
@property
def name(self):
print('getter')
return self.__name
@name.setter
def name(self, input_name):
print('setter')
self.__name = input_name
a = A('hoge')
a.name
# getter
# 'hoge'
a.name = 'add text'
# setter
a.name
# getter
# 'add text'
a.__name
# __name 属性にはアクセスできない
# AttributeError: 'A' object has no attribute '__name'
# しかし、規則を知っていればアクセス可能になってしまう
a._A__name
# 'hoge'