Python @propertyデコレータマスター:クリーンで後方互換なゲッター/セッター
Python @propertyデコレータマスター
Pythonの組み込み@propertyデコレータが如何に簡潔で保守しやすいゲッター/セッターを書きながらAPIの後方互換性を保つかを学びます。
Pythonの@propertyデコレータは属性アクセスのカプセル化に強力なツールです。属性読み書き時にカスタムロジックを実行させつつ、呼び出し側コード変更を強制しません。以下では実例—温度変換処理—を通じて制約強制方法を示し、なぜ@propertyがイディオマチックな解決策かを説明します。
ゲッター/セッターなしのクラス
摂氏で温度を格納し、華氏変換可能なシンプルなクラスが必要とします:
class Celsius:
def __init__(self, temperature=0):
self.temperature = temperature
def to_fahrenheit(self):
return (self.temperature * 1.8) + 32
使用は簡単:
# 新オブジェクト作成
human = Celsius()
# 温度設定
human.temperature = 37
# 温度読み取り
print(human.temperature)
# 華氏変換
print(human.to_fahrenheit())
出力
37 98.60000000000001
浮動小数点結果はバイナリでの10進表現によるもの。human.__dict__を見ると、Pythonが値を普通の辞書エントリとして格納しているのがわかります:
>>> human.__dict__
{'temperature': 37}
ゲッター/セッターで制約追加
実世界オブジェクトは検証を必要とすることが多々あります。例えば温度は絶対零度(-273.15 °C)未満になりえません。単純な方法は属性を隠蔽し、明示的ゲッター/セッターメソッドを公開すること:
class Celsius:
def __init__(self, temperature=0):
self.set_temperature(temperature)
def to_fahrenheit(self):
return (self.get_temperature() * 1.8) + 32
# ゲッター
def get_temperature(self):
return self._temperature
# セッター
def set_temperature(self, value):
if value < -273.15:
raise ValueError("Temperature below -273.15 is not possible.")
self._temperature = value
これでクラスは下限を強制しますが、obj.temperatureでアクセスしていた既存コードはobj.get_temperature()とobj.set_temperature(val)呼び出しに書き換え必須。大規模コードベースでは大規模リファクタリングになります。
さらに、Pythonの「プライベート」変数は命名規約に過ぎず—_temperatureにも直接アクセス可能でカプセル化が破れます。ここで@propertyが真価を発揮します。
propertyクラスの使用
Pythonはゲッター/セッター関数を属性名に結びつけるpropertyクラスを提供:
class Celsius:
def __init__(self, temperature=0):
self.temperature = temperature
def to_fahrenheit(self):
return (self.temperature * 1.8) + 32
# ゲッター
def get_temperature(self):
print("Getting value...")
return self._temperature
# セッター
def set_temperature(self, value):
print("Setting value...")
if value < -273.15:
raise ValueError("Temperature below -273.15 is not possible")
self._temperature = value
# プロパティとして公開
temperature = property(get_temperature, set_temperature)
このセットアップでは、以下のコードが元のシンプルクラスと全く同じように振る舞いますが、裏で検証が働きます:
human = Celsius(37)
print(human.temperature) # ゲッター発火
print(human.to_fahrenheit()) # 内部でゲッター使用
human.temperature = -300 # セッター発火、ValueError発生
出力
Setting value... Getting value... 37 Getting value... 98.60000000000001 Setting value... Traceback (most recent call last): ... ValueError: Temperature below -273 is not possible
temperatureアクセスコードは変更不要;実装のみが検証を獲得しました。
ヒント:実際のデータは_temperatureに格納;temperatureは便利で安全なインターフェースに過ぎません。
@propertyデコレータ
propertyクラスでも動作しますが、Pythonのデコレータ構文ならよりクリーンで可読な同等結果が得られます。デコレータが自動的にプロパティオブジェクトを作成し、ゲッター/セッターを属性名に結びつけます。
class Celsius:
def __init__(self, temperature=0):
self.temperature = temperature
def to_fahrenheit(self):
return (self.temperature * 1.8) + 32
@property
def temperature(self):
print("Getting value...")
return self._temperature
@temperature.setter
def temperature(self, value):
print("Setting value...")
if value < -273.15:
raise ValueError("Temperature below -273 is not possible")
self._temperature = value
使用方法は同じ:
human = Celsius(37)
print(human.temperature)
print(human.to_fahrenheit())
# 無効温度設定試行
try:
Celsius(-300)
except ValueError as e:
print(e)
出力
Setting value... Getting value... 37 Getting value... 98.60000000000001 Setting value... Traceback (most recent call last): ... ValueError: Temperature below -273 is not possible
@property使用で名前空間が整理され、別個のゲッター/セッターメソッド名が不要になり、ほとんどのPython開発者に推奨されるパターンです。
Python
- Python データ型マスター: 実践ガイド
- Python 演算子完全マスター: 包括的ガイド
- Python pass文完全マスター: 実践ガイド
- Python 関数引数完全マスター: 位置引数・キーワード引数・デフォルト引数
- Python辞書完全ガイド:作成、操作、高度なテクニック
- Python継承マスター:概念、構文、実践例
- Python演算子オーバーロード完全ガイド:__add__、__lt__など特殊メソッドでOOP設計を強化
- Pythonイテレータ完全ガイド:仕組みと自作方法
- Pythonクロージャ解説:ネスト関数が変数を捕捉する仕組み
- Python @propertyデコレータマスター:クリーンで後方互換なゲッター/セッター
- Python datetimeマスター:日付・時刻・タイムゾーン実践ガイド