2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

まえがき

私が資格取得もかねて Python の基礎知識を見直していたところ、Python の getter/setter にはいろいろ書き方があることを知りました。業務で 1 年半 Python を書いてきて「もう使いこなしているぞ」という段階においてです。

プログラミング経験者で他の言語を習得しようとするときには、概念だけを知っている状態でとりあえず実装してみようとなる人もいますが、このときに、習得しようとしている言語にもっと便利な書き方があることに気付かず、すでに知っている言語と同じような書き方で終わってしまうことがあります。

備忘録を兼ねつつ、Python を学習中の方にも、すでに習得しているという方にも知っていてほしいと思ったので、今回の記事を書くことにします。

前提

この記事では、getter/setter の概念は習得済みであるとします。
deleter については省略します。
また、getter/setter の是非論については扱いません。

Python での getter/setter の書き方

今回、私が知っている 3 通りの方法をご紹介しますが、言語仕様に即した他の書き方がもしありましたら、コメントでお寄せいただけると幸いです。

今回は、本の価格をプロパティに持つ BookPrice クラスを作成します。

get_* や set_* といったメソッドを用意する

おそらく最も知られている方法かと思います。

get_price を getter、set_price を setter のメソッドとします。
プロパティ名を __price のように __(アンダースコア 2 つ)で始めるとプライベートになります。

sample1.py
from typing import Optional


class BookPrice:
    def __init__(self) -> None:
        self.__price: Optional[int] = None
    
    def get_price(self) -> int:
        print('getter called')
        return self.__price
    
    def set_price(self, value: int) -> None:
        print('setter called')
        self.__price = value

book_price = BookPrice()
book_price.set_price(1200)
print(book_price.get_price())

価格を取得したいときは get_price メソッドを実行し、価格を設定したい場合は set_price の引数に価格を指定して実行します。

実行すると以下のようになります。

$ python sample1.py
setter called
getter called
1200

property クラスをインスタンス化する

Python で property について調べると最初に出てくる書き方ですが、私はこの記事を書いていて初めて知りました。

sample2.py
from typing import Optional


class BookPrice:
    def __init__(self) -> None:
        self.__price: Optional[int] = None
    
    def get_price(self) -> int:
        print('getter called')
        return self.__price
    
    def set_price(self, value: int) -> None:
        print('setter called')
        self.__price = value
    
    price = property(fget=get_price, fset=set_price, fdel=None, doc='本の価格')

book_price = BookPrice()
book_price.price = 1200
print(book_price.price)

get_priceset_price を用意するところまでは先ほどの方法と同じですが、最後に property クラスをインスタンス化する形でプロパティを設定します。
getter/setter/deleter およびプロパティの説明を指定します。

価格を取得したいときは book_price.price で、価格を設定したい場合は book_price.price = 1200 のようにします。
呼び出し側では、price というプロパティに対して値を直接取得したり設定したりしているように見えます。

実行すると以下のようになります。

$ python sample2.py
setter called
getter called
1200

property クラスをデコレータに使用する

私は Python の資格の勉強で知りました。

sample3.py
from typing import Optional


class BookPrice:
    def __init__(self) -> None:
        self.__price: Optional[int] = None
    
    @property
    def price(self) -> int:
        """本の価格"""
        print('getter called')
        return self.__price
    
    @price.setter
    def price(self, value: int) -> None:
        print('setter called')
        self.__price = value

book_price = BookPrice()
book_price.price = 1200
print(book_price.price)

呼び出し方は先ほどの方法と同じですが、クラスの実装が少し異なります。
getter には @property デコレータを設定し、メソッド名はプロパティ名の price にします。setter には @{プロパティ名}.setter デコレータを設定し、メソッド名は getter と同じで price にします。

同じ名前のメソッドが複数存在するため、違和感がありますが、これで問題ないようです。
また、setter のデコレータで price なんて補完されるのかよ、という感じですが、VSCode および PyCharm においては、getter が存在することでプロパティ名が自動補完できるようなので、開発者体験としても問題ありません。

実行すると以下のようになります。

$ python sample3.py
setter called
getter called
1200

まとめ

Python の getter/setter は、調べてみると方法が 3 通りあったわけですが、こんなに方法があることに気付くには、 実装方法を知っていても改めて調べてみる ことが必要でした。
実務においても、要件を満たせばそれでよいのではなく、時間の許す限り、より良い書き方を求めていきたいと思いました。

2
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?