スポンサーリンク

Pythonの@propertyデコレーターとは?getter・setterの使い方をわかりやすく解説!

Python入門

はじめに|Pythonでインスタンス変数を“いい感じ”に制御したい人へ

Pythonでクラスを使ってプログラムを作っていると、「この変数は自由に変更されたくないな…」「値を設定するときにチェックを入れたいな…」と思う場面、けっこうありませんか?

そんなときに便利なのが、**プロパティデコレーター(@property)**です。

この機能を使うと、インスタンス変数へのアクセスをまるで直接アクセスしているかのようなシンプルな書き方のままで、内部ではしっかり制御された処理を挟むことができるんです。

つまり、

user.name = "Alice"

と書いている裏で、ちゃんと「それ、文字列?大丈夫?」ってチェックしてくれるような仕組みを入れられるわけですね。

この「直感的に使えるけど中身はしっかりしてる」感じ、Pythonらしいクラス設計の肝とも言えます。

この記事では、そんな@propertyの使い方や仕組みを、初心者にもわかるように丁寧に解説していきます!

「getter? setter? なんか面倒そう…」と思っていた方も、読み終わるころには「なんだ、簡単じゃん!」と思えるようになるはずです。

それではさっそく見ていきましょう!




1. プロパティデコレーターとは?

まず、プロパティデコレーター(@property)とは何なのか?から見ていきましょう。

簡単に言うと、クラスの中の変数(インスタンス変数)にアクセスする方法をカスタマイズできる機能です。
それでいて、外側から見ると 普通に変数にアクセスしているように見える というのがポイントです。


なぜ必要なの?

たとえば、こんなクラスを考えてみます。

class User:
def __init__(self, name):
self.name = name

この User クラスを使ってみると…

user = User("Alice")
print(user.name) # → Alice
user.name = 123 # ← これ、文字列じゃないけど代入できちゃいます…

このように、誰でも何でも name に入れることができてしまいます。
これだと「名前は必ず文字列にしたい!」という意図が守れません。


そこで登場するのが @property

この問題を解決するために、以前は「ゲッター(get)とセッター(set)を使おう」という考え方がありました。

class User:
def __init__(self, name):
self._name = name

def get_name(self):
return self._name

def set_name(self, value):
if not isinstance(value, str):
raise ValueError("名前は文字列である必要があります")
self._name = value

でもこれ、毎回 get_name()set_name() を呼ばないといけないのがちょっと面倒ですし、Pythonらしい書き方とは言えません

そこで出てくるのが @property なんです。

このデコレーターを使うと、こんなふうに書けるようになります:

class User:
def __init__(self, name):
self._name = name

@property
def name(self):
return self._name

@name.setter
def name(self, value):
if not isinstance(value, str):
raise ValueError("名前は文字列である必要があります")
self._name = value

これでどうなるかというと…

user = User("Alice")
print(user.name) # → Alice(getterが呼ばれる)
user.name = "Bob" # setterが呼ばれる。OK!
user.name = 123 # setterが呼ばれてエラーになる!

つまり、外からは普通の変数っぽく使えるけど、中ではちゃんとチェック処理が走るという仕組みになっているんです。便利ですよね。




2. 通常のゲッター・セッターとの違いとメリット

Pythonでインスタンス変数の操作に制御を加えたいとき、よくあるのが「ゲッター」「セッター」という手法です。これは多くのプログラミング言語で定番のやり方です。

でも実は、この「伝統的な方法」には、Pythonならではの“ちょっとした違和感”があるんです。


ゲッター・セッターの従来の使い方

たとえば、あるユーザーの「年齢」が0歳未満にならないようにしたい場合、こんなコードになります:

class User:
def __init__(self, age):
self._age = None
self.set_age(age)

def get_age(self):
return self._age

def set_age(self, value):
if value < 0:
raise ValueError("年齢は0以上である必要があります")
self._age = value

使うときはこんな感じです:

user = User(20)
print(user.get_age()) # → 20
user.set_age(25) # OK
user.set_age(-5) # エラー!

うーん、毎回 get_age()set_age() を書くのって、ちょっと面倒ですよね?
Pythonってもっとスッキリ書けるイメージがあるはず…。


@propertyを使えば、見た目がスッキリ!

上の例を @property を使って書き直すとこうなります:

class User:
def __init__(self, age):
self._age = None
self.age = age

@property
def age(self):
return self._age

@age.setter
def age(self, value):
if value < 0:
raise ValueError("年齢は0以上である必要があります")
self._age = value

そして使い方はこんなにシンプル:

user = User(20)
print(user.age) # → 20(getterが呼ばれる)
user.age = 30 # setterが呼ばれる。OK!
user.age = -1 # setterが呼ばれてエラー!

関数っぽく見えないのに関数が動いてるって、ちょっと不思議でおもしろいですよね。


Pythonらしさが生きる!

Pythonは「読みやすく、書きやすい」コードを書くことが重視される言語です。

user.age のように、まるで普通の変数のように扱えるのに、実は中で処理が走ってる
この仕組みがあることで、コードが読みやすく、エラーに強く、保守性もアップします。

そしてなにより、あとから制御処理を追加したくなったときも楽!
最初は普通の変数にしておいて、必要になったら @property に切り替えればOK。外部のコードを変えずに内部のロジックだけ強化できます。

このように、@property は「便利・安全・Pythonらしい」三拍子揃った仕組みなんです!




3. @property の使い方と実装例

ここからは、実際に @property を使ったクラスの例を見ながら、どうやってゲッター・セッターを定義するのかを学んでいきましょう。


基本の書き方

まずは、「名前(name)」という変数に対して、文字列だけを許可したいというシンプルな例から。

class User:
def __init__(self, name):
self._name = name # 実際にデータを保持する内部変数

@property
def name(self):
# ゲッター:nameを取得する時に呼ばれる
return self._name

@name.setter
def name(self, value):
# セッター:nameを設定する時に呼ばれる
if not isinstance(value, str):
raise ValueError("名前は文字列である必要があります")
self._name = value

ここでのポイントは3つ:

  1. @property を使って、ゲッター(値の取得) を定義
  2. @xxx.setter を使って、セッター(値の設定) を定義
  3. _name という内部用の変数に実際のデータを保持する

使い方を見てみよう

このクラスを使って、インスタンスを操作してみましょう。

user = User("Alice")
print(user.name) # → Alice(getterが呼ばれる)

user.name = "Bob" # setterが呼ばれる(OK)
print(user.name) # → Bob

user.name = 123 # setterが呼ばれる(エラー!)
# → ValueError: 名前は文字列である必要があります

外から見ると user.name = "Bob" のように普通に変数に代入しているように見えますが、
実は内部ではセッターが動いていて、値のチェックが行われているんです。


なぜわざわざ _name を使うの?

Pythonには「完全なプライベート変数」はありませんが、_name のようにアンダースコアを付けることで、

「これは内部用の変数ですよ、外から直接触らないでくださいね」

というお約束(慣習)を示しています。

このおかげで、name という表向きの名前と _name という裏側のデータを分けて使えるようになるんですね。




4. ゲッターだけ定義する読み取り専用プロパティ

@property デコレーターは、ゲッターとセッターの両方に使える…というのはすでに説明しましたね。
でも実は、ゲッターだけを定義して、「読み取り専用」のプロパティを作ることもできるんです。


読み取り専用プロパティの例

以下の例では、ユーザーの登録日(created_at)を読み取り専用にしています。

import datetime

class User:
def __init__(self, name):
self._name = name
self._created_at = datetime.datetime.now()

@property
def created_at(self):
return self._created_at

ここでのポイント:

  • created_atにはセッターが定義されていません
  • 外部からは読み取りはできるけど、書き換えようとするとエラーになります

試してみよう!

user = User("Alice")
print(user.created_at) # → 登録日時を表示

user.created_at = "今日" # → エラー!書き換えできない!
# AttributeError: can't set attribute

このように、「外から勝手に変えられてほしくない変数」にぴったりです。
たとえばユーザーIDや生成時刻など、一度設定したら変わってはいけない情報に使えますね。




5. デリーター(deleter)の使い方

ちょっとマニアックですが、@property には**削除処理をカスタマイズできる「デリーター」**という機能もあります。


デリーターって何?

変数を del オブジェクト.変数 で削除したときに、特定の処理を実行させることができるんです。


例:nameを削除したらログを出す

class User:
def __init__(self, name):
self._name = name

@property
def name(self):
return self._name

@name.deleter
def name(self):
print(f"{self._name} を削除しました")
del self._name

これを使ってみると…

user = User("Alice")
del user.name # → Alice を削除しました
print(user.name) # → AttributeError

削除された後にアクセスすると、当然エラーになります。
「どうしても削除させたい変数」があるときに使えるテクニックですね。


注意点

  • deleter はあまり使う場面が多くありません
  • どちらかというと「特殊な事情があるとき」向けです
  • 削除後のアクセスでエラーが出る点には注意しましょう

これで、@property に関する ゲッター/セッター/デリーター の使い方はすべて網羅できました!




まとめ|プロパティで“安全でスマートなクラス”を作ろう

この記事では、Pythonの @property デコレーターについて、基本から応用までじっくり解説してきました。

クラスの中でデータをしっかり守りつつ、外からはシンプルな形でアクセスできる。
これこそが、@property を使う最大のメリットです。


この記事で学んだこと

@property を使うことで、インスタンス変数にアクセスする時の振る舞いを制御できる

✅ ゲッター/セッターを定義して、値のチェックや加工処理を内部でこっそり実行できる

✅ セッターを省略すれば、読み取り専用の変数にできる

deleter を使えば、削除処理にも独自の挙動を加えられる


実務やアプリ開発にも活かせる!

例えば…

  • 入力された年齢や金額が正しいか自動チェックしたい
  • 一度決めたユーザーIDを変更不可にしたい
  • 設定を変更されたときに内部処理を走らせたい

といった場面で @property は大活躍します。

ただの変数じゃ物足りないとき、処理を中に忍ばせたいとき、ぜひ思い出してください!

次はぜひ、複数のプロパティを組み合わせたり、他のデコレーターと一緒に使ったりして、より高度なクラス設計にもチャレンジしてみましょう!


あわせて読みたい

以下の記事も、Pythonのクラスやデコレーターの理解を深めるのにおすすめです!


よくある質問(Q&A)

Q
@property を使うとパフォーマンスに影響しますか?
A

通常の使い方であれば、ほとんどパフォーマンスへの影響はありません。繰り返しアクセスされるような場面では、必要に応じてキャッシュを使うとさらに効率的です。

Q
セッターだけ使うことはできますか?
A

いいえ。@property(ゲッター)を定義しないと @name.setter は使えません。必ずゲッター → セッターの順で定義する必要があります。

Q
変数を削除することって実際ありますか?
A

あまり一般的ではありませんが、デバッグ目的や一時的なメモリ解放、特別な状態管理などで使われることがあります。通常のアプリ開発では必須ではない機能です。

※当サイトはアフィリエイト広告を利用しています。リンクを経由して商品を購入された場合、当サイトに報酬が発生することがあります。

※本記事に記載しているAmazon商品情報(価格、在庫状況、割引、配送条件など)は、執筆時点のAmazon.co.jp上の情報に基づいています。
最新の価格・在庫・配送条件などの詳細は、Amazonの商品ページをご確認ください。

スポンサーリンク