6.8 プロパティによる属性値の取得、設定
他のオブジェクト指向言語では、属性を非公開にして直接アクセスできないようにし、代わりに「ゲッター(取得用)」と「セッター(設定用)」と呼ばれるメソッドを書くことがよくあります。 しかし、Pythonではすべての属性とメソッドが公開されているため、基本的にはゲッターやセッターをわざわざ書く必要はありません。
それでも、属性への直接アクセスを避けたい場合や、値の取得・設定時に特定の処理を挟みたい場合には、Pythonらしい方法である 「プロパティ」 を使います。
property() 関数を使った定義
Section titled “property() 関数を使った定義”まずは、hidden_name という属性を持つ Duck クラスを作り、通常のゲッターとセッターメソッドを定義してから、それをプロパティとして設定する方法を見てみましょう。
class Duck(): def __init__(self, input_name): self.hidden_name = input_name
def get_name(self): print('inside the getter') return self.hidden_name
def set_name(self, input_name): print('inside the setter') self.hidden_name = input_name
# ゲッターとセッターを name というプロパティとして定義 name = property(get_name, set_name)このように定義すると、name 属性のようにアクセスするだけで、裏では自動的に get_name() や set_name() が呼び出されるようになります。
fowl = Duck('Howard')
# 属性のようにアクセスすると、ゲッターが呼ばれるprint(fowl.name)# 出力:# inside the getter# Howard
# 属性のように代入すると、セッターが呼ばれるfowl.name = 'Daffy'# 出力: inside the setterデコレータを使った定義(推奨)
Section titled “デコレータを使った定義(推奨)”プロパティは、デコレータ(@ から始まるキーワード)を使うと、より簡潔で直感的に定義できます。
@property: ゲッターメソッドの直前に付けます。@プロパティ名.setter: セッターメソッドの直前に付けます。
class Duck(): def __init__(self, input_name): self.hidden_name = input_name
# ゲッターの定義 @property def name(self): print('inside the getter') return self.hidden_name
# セッターの定義(メソッド名はゲッターと同じにします) @name.setter def name(self, input_name): print('inside the setter') self.hidden_name = input_nameこの書き方でも、先ほどと同様に fowl.name でゲッターやセッターが呼び出されます。
計算されたプロパティと読み出し専用プロパティ
Section titled “計算されたプロパティと読み出し専用プロパティ”プロパティの素晴らしい点は、単に値を返すだけでなく、他の属性から計算された値をプロパティとして提供できることです。
また、セッター(@プロパティ名.setter)を定義しなければ、読み出し専用のプロパティを作ることができます。
class Circle(): def __init__(self, radius): # radius(半径)は通常の属性 self.radius = radius
# diameter(直径)は radius から計算されるプロパティ @property def diameter(self): return 2 * self.radiusこの Circle オブジェクトの動作を確認してみましょう。
c = Circle(5)print(c.radius) # 5print(c.diameter) # 10 (2 * 5 が計算されて返る)
# 半径を変更すると、直径も連動して変わるc.radius = 7print(c.diameter) # 14読み出し専用プロパティの保護
Section titled “読み出し専用プロパティの保護”diameter にはセッターが定義されていないため、外部から直接値を書き換えようとするとエラーになります。
# c.diameter = 20# 出力結果(エラー): AttributeError: can't set attribute