Smile Engineering Blog

ジェイエスピーからTipsや技術特集、プロジェクト物語を発信します

Pythonでプロパティを実装する

今回は、Pythonでのプロパティの実装方法を解説します。

プロパティとは?

ここで取り扱うプロパティとは、クラス利用者がそのメンバ変数にアクセスするときにgetterやsetterを意識することなくアクセス出来るようにする仕組みです。

通常、クラスを実装するときはメンバ変数を直接外部に公開せず、プライベートにしつつ、別途getterとsetterを用意します。これをカプセル化と呼びます。よって、クラス利用者はgetterやsetterを介してメンバ変数にアクセスします。

class Name1:
    def __init__(self):
        self._firstname = ''
        self._lastname = ''

    def get_firstname(self):
        return self._firstname

    def set_firstname(self, firstname):
        self._firstname = firstname

    def get_lastname(self):
        return self._lastname

    def set_lastname(self, lastname):
        self._lastname = lastname

    def get_fullname(self):
        return self._firstname + self._lastname

name = Name1()
name.set_firstname('Fugataro')
name.set_lastname('Hogemoto')
print(name.get_firstname())
print(name.get_lastname())
print(name.get_fullname())

# Fugataro
# Hogemoto
# FugataroHogemoto

しかし、プロパティを用いることで、カプセル化を維持しつつ、クラス利用者はgetterやsetterを意識することなくメンバ変数にアクセス出来るようになります。

Pythonでプロパティを実装する方法は2通りあるため、両方解説していきます。

property関数を用いる方法

1つ目はproperty関数を用いる方法です。

まず、今まで通りにgetterとsetterを宣言します。そして、property関数に先ほど宣言したgetterとsetterの関数名を渡します。こうすることにより、クラス利用者はインスタンス名.メンバ変数名のフォーマットでメンバ変数にアクセス出来るようになりつつ、クラス内部では、先ほどproperty関数に渡したgetterとsetterを経由して、メンバ変数の受け渡しが行われます。

class Name2:
    def __init__(self):
        self._firstname = ''
        self._lastname = ''

    def get_firstname(self):
        return self._firstname

    def set_firstname(self, firstname):
        self._firstname = firstname

    def del_firstname(self):
        del self._firstname

    firstname = property(
        get_firstname, set_firstname, del_firstname
        )

    def get_lastname(self):
        return self._lastname

    def set_lastname(self, lastname):
        self._lastname = lastname

    def del_lastname(self):
        del self._lastname

    lastname = property(
        get_lastname, set_lastname, del_lastname
        )

    def get_fullname(self):
        return self._firstname + self._lastname

    fullname = property(get_fullname)

name = Name2()
name.firstname = 'Fugataro'
name.lastname = 'Hogemoto'
print(name.firstname)
print(name.lastname)
print(name.fullname)

# Fugataro
# Hogemoto
# FugataroHogemoto

また、メンバ変数をdelする関数も登録することが出来ます。以下サンプルソースでは実際にメンバ変数をdelしていますが、delした後にそのメンバ変数にアクセスすると例外が発生するため、delが正常に機能していることがわかります。

name = Name2()
name.firstname = 'Fugataro'
print(name.firstname)
del name.firstname
print(name.firstname)

# Fugataro
# AttributeError: 'Name2' object has no attribute '_firstname'

デコレータを用いる方法

2つ目はデコレータを用いる方法です。

デコレータを用いる場合も、getter、setter、deleterを宣言しますが、それら関数に、@property@メンバ変数名.setter@メンバ変数名.deleterを付与するだけです。

class Name3:
    def __init__(self):
        self._firstname = ''
        self._lastname = ''

    @property
    def firstname(self):
        return self._firstname

    @firstname.setter
    def firstname(self, firstname):
        self._firstname = firstname

    @firstname.deleter
    def firstname(self):
        del self._firstname

    @property
    def lastname(self):
        return self._lastname

    @lastname.setter
    def lastname(self, lastname):
        self._lastname = lastname

    @lastname.deleter
    def lastname(self):
        del self._lastname

    @property
    def fullname(self):
        return self._firstname + self._lastname

name = Name3()
name.firstname = 'Fugataro'
name.lastname = 'Hogemoto'
print(name.firstname)
print(name.lastname)
print(name.fullname)

# Fugataro
# Hogemoto
# FugataroHogemoto
name = Name3()
name.firstname = 'Fugataro'
print(name.firstname)
del name.firstname
print(name.firstname)

# Fugataro
# AttributeError: 'Name3' object has no attribute '_firstname'

参考

class property

カプセル化