@propertyのメモ書き【Python】

目次

結論。自分の理解まとめ。

普段、とある変数を参照したり、値を更新したりするけど、

(print(instance.val) # 参照したり、instance.val = “値を変えるよ” # 更新したり)

参照の際には文字を追加したり、空白は更新できないようにしたい場合は、ゲッター関数やセッター関数を作って、それ経由で参照更新していました。

そうすると、変数にアクセスするというより、関数を実行する感覚になります。
それは嫌だが、追加処理等もしっかりしたい。

そんな場合にプロパティを使えば、単に変数を利用している風に見えつつ、処理も動かせます

@propertyを実装してみて色々確かめる

PYTHONCOPY
class Test:
    def __init__(self, val):
        print('initの中')
        self.name = val
        print('initの終了')

    @property
    def name(self):
        print('propertyの中')
        return '名前:' + self.__name # ネームマングリングを利用して、無限ループを避けている。

    @name.setter
    def name(self, setVal):
        print('setterの中')
        if(setVal != ''):
            self.__name = setVal # ネームマングリングを利用して、無限ループを避けている
            print('setterの終了')

print('★インスタンス生成')
test = Test('taishi')
print(test.name)

print('★名前を空白にしてみる')
test.name = '' # ちなみにpropertyを定義すると、setterも定義しないと更新処理ができなくなる。他のdeleteも然り。
print(test.name)

print('★名前を別名に変更してみる')
test.name = '名前変わるよ'
print(test.name)

↓実行結果↓
★インスタンス生成
initの中
setterの中
setterの終了
initの終了
propertyの中
名前:taishi
★名前を空白にしてみる
setterの中
propertyの中
名前:taishi
★名前を別名に変更してみる
setterの中
setterの終了
propertyの中
名前:名前変わるよ

  • 確認1
    @propertyでデコレーションした関数が、name変数を参照しようとした際に動作している。
  • 確認2
    @name.setterでデコレーションした関数は、name変数を更新しようとした際に動作している。
  • 確認3
    プロパティは外部からだけでなく、内部からのアクセスでも動くように見える。(init関数より)

普段なら、ゲッターやセッター関数を作って、それを呼び出す形にすることで、値を取得したり更新したりする時に何かしらの付与や制限ができると思います。
その形だと、呼び出す側はあくまで関数を呼び出す必要がありましたが、プロパティを使えば、関数を意識することなく値を呼び出す感覚で記載できそうです。各プロパティが勝手に動いてくれるからですね。

プロパティ名は変数名と同じにする必要があるのか?

変数名をlocal_nameに変えてみました。あとは一緒。

PYTHONCOPY
class Test:
    def __init__(self, val):
        print('initの中')
        self.local_name = val # nameからlocal_nameに
        print('initの終了')

    @property
    def name(self):
        print('propertyの中')
        return '名前:' + self.local_name # nameからlocal_nameに

    @name.setter
    def name(self, setVal):
        print('setterの中')
        if(setVal != ''):
            self.local_name = setVal # nameからlocal_nameに
            print('setterの終了')

print('★インスタンス生成')
test = Test('taishi')
print(test.name)

print('★名前を空白にしてみる')
test.name = '' # ちなみにpropertyを定義すると、setterも定義しないと更新処理ができなくなる。他のdeleteも然り。
print(test.name)

print('★名前を別名に変更してみる')
test.name = '名前変わるよ'
print(test.name)

↓実行結果↓
★インスタンス生成
initの中
initの終了
propertyの中
名前:taishi
★名前を空白にしてみる
setterの中
propertyの中
名前:taishi
★名前を別名に変更してみる
setterの中
setterの終了
propertyの中
名前:名前変わるよ

問題なく動きました。変数名がプロパティ名と異なるので、init関数で値を更新する際にsetterは動かなくなったようです。

ということは、とある値をラッピングする感覚というより、あくまで関数呼び出しの簡略化っぽいのか・・・?
ただ、用途としては値をラッピングする感覚であっていると思います。ゲッターセッター関数を使うルールよりも、値を直接触っているように見えるし、値操作の制限も強制力高く設けられる気がします。

Weekly Most Popular
記事書いたりサイト運営してる人
シイタ / siita
シイタ / siita
現役サラリーマン/システムエンジニアです。 会社外でも、自分に自信を持って活躍できるようになりたい。金銭的にも安心できるようになりたい。という気持ちから技術向上や不労所得を得るために、日々活動することを記録し、共有していきます。