サザエさん一家で学ぶセッターとゲッターの使い方|カプセル化を理解しよう
![]() |
20万件以上の案件から、副業に最適なリモート・週3〜の案件を一括検索できるプラットフォーム。プロフィール登録でAIスカウトが自動的にマッチング案件を提案。市場統計や単価相場、エージェントの口コミも無料で閲覧可能なため、本業を続けながら効率的に高単価の副業案件を探せます。フリーランスボード |
| |
週2〜3日から働ける柔軟な案件が業界トップクラスの豊富さを誇るフリーランスエージェント。エンド直契約のため高単価で、週3日稼働でも十分な報酬を得られます。リモートや時間フレキシブルな案件も多数。スタートアップ・ベンチャー中心で、トレンド技術を使った魅力的な案件が揃っています。専属エージェントが案件紹介から契約交渉までサポート。利用企業2,000社以上の実績。ITプロパートナーズ |
| |
10,000件以上の案件を保有し、週3日〜・フルリモートなど柔軟な働き方に対応。高単価案件が豊富で、報酬保障制度(60%)や保険料負担(50%)など正社員並みの手厚い福利厚生が特徴。通勤交通費(月3万円)、スキルアップ費用(月1万円)の支給に加え、リロクラブ・freeeが無料利用可能。非公開案件80%以上、支払いサイト20日で安心して稼働できます。Midworks |
プログラミングを学んでいると「セッター」「ゲッター」という言葉を耳にしますよね。でも、「なぜわざわざこんな面倒なことをするの?」と疑問に思ったことはありませんか?
この記事では、国民的アニメ「サザエさん」の登場人物を例に、セッターとゲッターの概念を分かりやすく解説します。Pythonのサンプルコードを使って、実際に手を動かしながら学べる内容になっています。
この記事で学べること:
- セッターとゲッターの基本概念
- カプセル化のメリット
- Pythonでの実装方法(通常の方法とプロパティデコレータ)
- 実務で役立つベストプラクティス
目次
セッターとゲッターとは?
ゲッター(Getter) は、オブジェクトの属性値を取得するためのメソッドです。
セッター(Setter) は、オブジェクトの属性値を設定・変更するためのメソッドです。
これらは「カプセル化」というオブジェクト指向プログラミングの重要な概念の一部です。カプセル化とは、データ(属性)を外部から直接アクセスできないようにして、メソッドを通じてのみアクセスできるようにすることです。
なぜセッターとゲッターが必要なの?
直接属性にアクセスすればいいのに、なぜわざわざメソッドを経由するのでしょうか? その理由は以下の通りです。
1. データの妥当性チェック
年齢に-10を設定したり、名前に数字だけを設定したりするような、おかしなデータの登録を防ぐことができます。
2. データの保護
重要なデータを勝手に変更されないように守ることができます。
3. 内部実装の隠蔽
内部でどのようにデータを保持しているかを隠し、外部からは決められた方法でのみアクセスできるようにします。
4. 将来の変更に強い設計
後から処理を追加したり変更したりしても、外部のコードに影響を与えにくくなります。
サザエさん一家で実践! 基本的なセッターとゲッター
それでは、サザエさん一家の「サザエさん」を例に、Pythonでセッターとゲッターを実装してみましょう。
悪い例:直接アクセス
まずは、セッターとゲッターを使わない例を見てみましょう。
class SazaeSan:
def __init__(self, name, age):
self.name = name
self.age = age
# インスタンスを作成
sazae = SazaeSan("フグ田サザエ", 24)
print(f"{sazae.name}さんは{sazae.age}歳です")
# 直接変更できてしまう
sazae.age = -10 # おかしな値でもエラーにならない
print(f"{sazae.name}さんは{sazae.age}歳です") # -10歳と表示されてしまう
問題点: 年齢に負の数を設定できてしまい、データの整合性が保たれません。
良い例:セッターとゲッターを使った実装
次に、セッターとゲッターを使って改善してみましょう。
class SazaeSan: def __init__(self, name, age): self.__name = name # プライベート属性(アンダースコア2つ) self.__age = age # ゲッター:名前を取得 def get_name(self): return self.__name # セッター:名前を設定 def set_name(self, name): if not isinstance(name, str) or len(name) == 0: raise ValueError("名前は空でない文字列である必要があります") self.__name = name # ゲッター:年齢を取得 def get_age(self): return self.__age # セッター:年齢を設定 def set_age(self, age): if not isinstance(age, int) or age < 0 or age > 150: raise ValueError("年齢は0から150の整数である必要があります") self.__age = age def introduce(self): return f"はーい! {self.__name}です。{self.__age}歳です。" # 使用例 sazae = SazaeSan("フグ田サザエ", 24) print(sazae.introduce()) # ゲッターで取得 print(f"名前: {sazae.get_name()}") print(f"年齢: {sazae.get_age()}") # セッターで変更 sazae.set_age(25) print(f"誕生日を迎えて{sazae.get_age()}歳になりました!") # 不正な値を設定しようとするとエラーになる try: sazae.set_age(-10) except ValueError as e: print(f"エラー: {e}") try: sazae.set_name("") except ValueError as e: print(f"エラー: {e}")
実行結果:
はーい! フグ田サザエです。24歳です。
名前: フグ田サザエ
年齢: 24
誕生日を迎えて25歳になりました!
エラー: 年齢は0から150の整数である必要があります
エラー: 名前は空でない文字列である必要がありま
このように、セッターで入力値をチェックすることで、不正なデータの登録を防ぐことができます。
Pythonらしい書き方:@propertyデコレータ
Pythonには、もっとスマートにセッターとゲッターを実装する方法があります。それが @property デコレータ です。
これを使うと、メソッドなのに属性のようにアクセスできるようになります。
磯野家の人々を作ってみよう
サザエさんの実家、磯野家のメンバーをクラスで表現してみましょう。
class IsonoFamily:
def __init__(self, name, age, role):
self._name = name # プライベート属性(アンダースコア1つ)
self._age = age
self._role = role # 家族の役割
# 名前のゲッター
@property
def name(self):
return self._name
# 名前のセッター
@name.setter
def name(self, value):
if not isinstance(value, str) or len(value) == 0:
raise ValueError("名前は空でない文字列である必要があります")
self._name = value
# 年齢のゲッター
@property
def age(self):
return self._age
# 年齢のセッター
@age.setter
def age(self, value):
if not isinstance(value, int) or value < 0 or value > 150:
raise ValueError("年齢は0から150の整数である必要があります")
self._age = value
# 役割のゲッター(読み取り専用)
@property
def role(self):
return self._role
def introduce(self):
return f"{self._name}、{self._age}歳。家族の中では{self._role}です。"
# 磯野家のメンバーを作成
namihei = IsonoFamily("磯野波平", 54, "一家の大黒柱")
fune = IsonoFamily("磯野フネ", 52, "しっかり者の母")
katsuo = IsonoFamily("磯野カツオ", 11, "やんちゃな長男")
wakame = IsonoFamily("磯野ワカメ", 9, "元気な長女")
sazae = IsonoFamily("フグ田サザエ", 24, "長女で磯野家の元気印")
# @propertyを使うと属性のようにアクセスできる
print(namihei.introduce())
print(f"{katsuo.name}君は{katsuo.age}歳の{katsuo.role}")
# 誕生日を迎える
katsuo.age = 12 # セッターが呼ばれる
print(f"{katsuo.name}君は誕生日で{katsuo.age}歳になりました!")
# 不正な値を設定しようとするとエラー
try:
wakame.age = -5
except ValueError as e:
print(f"エラー: {e}")
# roleは読み取り専用なので変更できない
try:
namihei.role = "隠居"
except AttributeError as e:
print(f"役割は変更できません!")
実行結果:
磯野波平、54歳。家族の中では一家の大黒柱です。
磯野カツオ君は11歳のやんちゃな長男
磯野カツオ君は誕生日で12歳になりました!
エラー: 年齢は0から150の整数である必要があります
役割は変更できません!
@propertyのメリット
- シンプルな構文:
get_age()ではなくageでアクセスできる - Pythonicな書き方: Python らしい綺麗なコード
- 後方互換性: 既存のコードを壊さずに検証ロジックを追加できる
- 読み取り専用プロパティ: セッターを定義しなければ読み取り専用になる
実践例:タラちゃんの成長記録システム
もう少し実践的な例として、タラちゃんの成長を記録するシステムを作ってみましょう。
from datetime import datetime
class TaraChan:
def __init__(self, name, birth_year, height, weight):
self._name = name
self._birth_year = birth_year
self._height = height # cm
self._weight = weight # kg
@property
def name(self):
return self._name
@property
def age(self):
"""年齢は生年から計算(計算プロパティ)"""
current_year = datetime.now().year
return current_year - self._birth_year
@property
def height(self):
return self._height
@height.setter
def height(self, value):
if not isinstance(value, (int, float)) or value <= 0:
raise ValueError("身長は正の数である必要があります")
if value < 50 or value > 150:
raise ValueError("身長は50cm〜150cmの範囲で入力してください")
# 身長が急激に変化した場合は警告
if hasattr(self, '_height') and abs(value - self._height) > 30:
print(f"警告: 身長が急激に変化しています({self._height}cm → {value}cm)")
self._height = value
print(f"{self._name}の身長が{value}cmになりました!")
@property
def weight(self):
return self._weight
@weight.setter
def weight(self, value):
if not isinstance(value, (int, float)) or value <= 0:
raise ValueError("体重は正の数である必要があります")
if value < 5 or value > 50:
raise ValueError("体重は5kg〜50kgの範囲で入力してください")
self._weight = value
print(f"{self._name}の体重が{value}kgになりました!")
@property
def bmi(self):
"""BMIを計算(読み取り専用プロパティ)"""
height_m = self._height / 100
return round(self._weight / (height_m ** 2), 1)
def growth_report(self):
return (f"【{self._name}の成長記録】\n"
f"年齢: {self.age}歳\n"
f"身長: {self._height}cm\n"
f"体重: {self._weight}kg\n"
f"BMI: {self.bmi}")
# タラちゃんのインスタンスを作成
tara = TaraChan("フグ田タラオ", 2022, 90, 13)
print(tara.growth_report())
print()
# 1年後の健康診断
print("=== 1年後 ===")
tara.height = 95
tara.weight = 14.5
print()
print(tara.growth_report())
print()
# 年齢は計算プロパティなので変更できない
print(f"タラちゃんの年齢: {tara.age}歳")
# tara.age = 10 # これはエラーになる
# BMIも読み取り専用
print(f"BMI: {tara.bmi}")
# tara.bmi = 20 # これもエラーになる
実行結果:
【フグ田タラオの成長記録】
年齢: 3歳
身長: 90cm
体重: 13kg
BMI: 16.0
=== 1年後 ===
フグ田タラオの身長が95cmになりました!
フグ田タラオの体重が14.5kgになりました!
【フグ田タラオの成長記録】
年齢: 3歳
身長: 95cm
体重: 14.5kg
BMI: 16.1
タラちゃんの年齢: 3歳
BMI: 16.1
このように、セッターを使うことで:
- 値の妥当性チェック
- 変更時のログ出力
- 急激な変化の検知
などができるようになります。
プライベート属性の命名規則
Pythonではアンダースコアを使って属性のアクセスレベルを示します。
class Example:
def __init__(self):
self.public = "誰でもアクセス可能"
self._protected = "外部からアクセスしないでね(慣習)"
self.__private = "本当にアクセスしづらい(名前マングリング)"
| 記法 | 意味 | 使用例 |
|---|---|---|
self.name |
パブリック | 外部から自由にアクセス可能 |
self._name |
プロテクテッド | 「外部から触らないで」という慣習(実際はアクセス可能) |
self.__name |
プライベート | 名前マングリングで本当にアクセスしづらくなる |
推奨: @propertyと組み合わせる場合は _ (アンダースコア1つ)を使うのが一般的です。
よくある質問(FAQ)
Q1: すべての属性にセッターとゲッターが必要?
A: いいえ、必要ありません。以下の場合は直接アクセスで十分です。
- 検証が不要な単純なデータ
- クラス内部でのみ使う一時的な変数
- 変更の可能性が低い固定値
セッターとゲッターは「必要な時に」使うのが重要です。
Q2: get_xxx()とset_xxx()と@property、どちらを使うべき?
A: Pythonでは @property を使うのが推奨されています。理由は:
- Pythonicで読みやすい
- 既存のコードを壊さずに後から追加できる
- 計算プロパティを自然に表現できる
ただし、JavaやC++の経験者は get_xxx() スタイルに慣れているかもしれません。チームの規約に従いましょう。
Q3: 読み取り専用プロパティの使いどころは?
A: 以下のような場合に便利です。
- 計算で導き出される値(BMI、年齢など)
- 変更されてはいけない識別子
- 他の属性から派生する値
@property
def full_name(self):
return f"{self.last_name} {self.first_name}"
まとめ:セッターとゲッターを使いこなそう
セッターとゲッターは、以下のメリットをもたらします。
データの安全性
- 不正な値の登録を防ぐ
- データの整合性を保つ
保守性の向上
- 内部実装を隠蔽できる
- 後から機能を追加しやすい
デバッグの容易さ
- 値の変更時にログを出力できる
- 問題の原因を特定しやすい
Pythonでは@propertyデコレータを使うことで、シンプルかつ強力にカプセル化を実現できます。
学習のポイント
- まずはシンプルに: 最初は基本的な検証だけでOK
- 必要に応じて追加: 後から検証ロジックを追加できる
- 読みやすさを重視: 過度な抽象化は避ける
- 実践で学ぶ: 実際にコードを書いて試してみる
サザエさん一家のように、家族それぞれに個性があるように、クラスの属性もそれぞれに適した保護方法があります。この記事で学んだセッターとゲッターの知識を活かして、より堅牢なプログラムを作成していきましょう!
参考リンク
関連キーワード: Python カプセル化, オブジェクト指向 Python, Pythonプロパティ, Python初心者, プログラミング入門
![]() |
20万件以上の案件から、副業に最適なリモート・週3〜の案件を一括検索できるプラットフォーム。プロフィール登録でAIスカウトが自動的にマッチング案件を提案。市場統計や単価相場、エージェントの口コミも無料で閲覧可能なため、本業を続けながら効率的に高単価の副業案件を探せます。フリーランスボード |
| |
週2〜3日から働ける柔軟な案件が業界トップクラスの豊富さを誇るフリーランスエージェント。エンド直契約のため高単価で、週3日稼働でも十分な報酬を得られます。リモートや時間フレキシブルな案件も多数。スタートアップ・ベンチャー中心で、トレンド技術を使った魅力的な案件が揃っています。専属エージェントが案件紹介から契約交渉までサポート。利用企業2,000社以上の実績。ITプロパートナーズ |
| |
10,000件以上の案件を保有し、週3日〜・フルリモートなど柔軟な働き方に対応。高単価案件が豊富で、報酬保障制度(60%)や保険料負担(50%)など正社員並みの手厚い福利厚生が特徴。通勤交通費(月3万円)、スキルアップ費用(月1万円)の支給に加え、リロクラブ・freeeが無料利用可能。非公開案件80%以上、支払いサイト20日で安心して稼働できます。Midworks |








