積雲が映像制作したMV『RANGEFINDER』公開中
専門88IO

【Python】プロパティによるアクセス制御の実装/使用例

専門

Pythonではプロパティを用いることでゲッタ, セッタ等のアクセス制御を行うことができる。

デコレータ@propertyでプロパティを定義し、@property.getter, @property.setterで制御する。また、以下のサンプルコードのように@property.getter@propertyに統合することができる。

class TestClass:
    def __init__(self, value):
        self.__value = value
 
    # プロパティ定義+ゲッタ   
    @property
    def value(self):
        return self.__value

    # セッタ
    @value.setter
    def value(self, val):
        self.__value = val

これにより、

test = TestClass(10)
print(test.value)  # -> 10
test.value = 5
print(test.value)  # -> 5

のようにインスタンス変数と同様の方法でアクセスできる。

インスタンス変数__value自体は外部からの参照できないように変数名をアンダースコア2つ__から始め、マングリング機能により擬似的なプライベート変数として扱えるようにしている。主にセッタでは代入値が適切であるか確認する処理を行うため、直接メンバにアクセスできるとバグの原因になりかねない。

これを踏まえると、代入時に型チェックを行うサンプルコードは以下のようになる。初期化時に代入する値に対しても型チェックを行うためにself.__datetimeではなくself.datetimeに代入する点に注意。

from datetime import datetime as Datetime
from discord import Member, User

class Task:
    def __init__(self, datetime, member):
        self.datetime = datetime
        self.member = member

    @property
    def datetime(self):
        return self.__datetime

    @datetime.setter
    def datetime(self, value):
        if not isinstance(value, Datetime):
            raise TypeError("type of 'datetime' must be datetime.datetime")
        self.__datetime = value

    @property
    def member(self):
        return self.__member

    @member.setter
    def member(self, value):
        if not isinstance(value, (Member, User)):
            raise TypeError("type of 'member' must be Union[discord.Member, discord.User]")
        self.__member = value

コメント

タイトルとURLをコピーしました