getter・setter完全マスターガイド – 日本一わかりやすいアクセサメソッド入門
getter・setterとは?基本概念を3分で理解
**getter(ゲッター)とsetter(セッター)**は、オブジェクト指向プログラミングにおけるアクセサメソッドです。クラスの内部データ(プロパティ)に安全にアクセスするための仕組みで、データの読み取り(getter)と書き込み(setter)を制御します。
getter・setterの役割
| メソッド | 役割 | 例 |
|---|---|---|
| getter | データを取得する | getName(), getAge() |
| setter | データを設定する | setName(), setAge() |
| プロパティ | 直接的なデータ操作 | person.name, person.age |
基本的なgetter・setterの実装
Java での実装
public class Person {
private String name;
private int age;
// getter
public String getName() {
return name;
}
// setter
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age >= 0) {
this.age = age;
}
}
}
Python での実装
class Person:
def __init__(self):
self._name = ""
self._age = 0
# getter
@property
def name(self):
return self._name
# setter
@name.setter
def name(self, value):
self._name = value
@property
def age(self):
return self._age
@age.setter
def age(self, value):
if value >= 0:
self._age = value
# 使用例
person = Person()
person.name = "太郎" # setterが呼ばれる
print(person.name) # getterが呼ばれる
JavaScript での実装
class Person {
constructor() {
this._name = "";
this._age = 0;
}
// getter
get name() {
return this._name;
}
// setter
set name(value) {
this._name = value;
}
get age() {
return this._age;
}
set age(value) {
if (value >= 0) {
this._age = value;
}
}
}
// 使用例
const person = new Person();
person.name = "太郎"; // setterが呼ばれる
console.log(person.name); // getterが呼ばれる
なぜgetter・setterが必要なのか?
1. データの保護(カプセル化)
# ❌ 直接アクセス(問題のある例)
class BankAccount:
def __init__(self):
self.balance = 0 # 外部から直接変更可能
account = BankAccount()
account.balance = -1000 # 負の残高!問題あり
# ✅ getter・setterで保護
class SafeBankAccount:
def __init__(self):
self._balance = 0
@property
def balance(self):
return self._balance
@balance.setter
def balance(self, amount):
if amount >= 0:
self._balance = amount
else:
raise ValueError("残高は0以上である必要があります")
2. バリデーション(入力検証)
class User:
def __init__(self):
self._email = ""
self._password = ""
@property
def email(self):
return self._email
@email.setter
def email(self, value):
if "@" in value and "." in value:
self._email = value
else:
raise ValueError("有効なメールアドレスを入力してください")
@property
def password(self):
return "***" # パスワードは表示しない
@password.setter
def password(self, value):
if len(value) >= 8:
self._password = value
else:
raise ValueError("パスワードは8文字以上必要です")
3. 計算プロパティ
class Rectangle:
def __init__(self, width, height):
self._width = width
self._height = height
@property
def width(self):
return self._width
@width.setter
def width(self, value):
if value > 0:
self._width = value
@property
def height(self):
return self._height
@height.setter
def height(self, value):
if value > 0:
self._height = value
@property
def area(self): # 計算プロパティ(setterなし)
return self._width * self._height
rect = Rectangle(5, 3)
print(rect.area) # 15(自動計算)
実践的なgetter・setter活用例
1. 温度変換クラス
class Temperature:
def __init__(self, celsius=0):
self._celsius = celsius
@property
def celsius(self):
return self._celsius
@celsius.setter
def celsius(self, value):
if value >= -273.15: # 絶対零度チェック
self._celsius = value
else:
raise ValueError("絶対零度以下は設定できません")
@property
def fahrenheit(self):
return self._celsius * 9/5 + 32
@fahrenheit.setter
def fahrenheit(self, value):
self.celsius = (value - 32) * 5/9
temp = Temperature()
temp.celsius = 25
print(temp.fahrenheit) # 77.0
temp.fahrenheit = 100
print(temp.celsius) # 37.77...
2. データベース接続管理
class DatabaseConnection:
def __init__(self):
self._host = "localhost"
self._port = 5432
self._connected = False
@property
def host(self):
return self._host
@host.setter
def host(self, value):
if self._connected:
raise RuntimeError("接続中は変更できません")
self._host = value
@property
def connection_string(self):
return f"postgresql://{self._host}:{self._port}/db"
def connect(self):
self._connected = True
def disconnect(self):
self._connected = False
3. ショッピングカート
class ShoppingCart:
def __init__(self):
self._items = []
self._tax_rate = 0.10
@property
def items(self):
return self._items.copy() # コピーを返して直接変更を防ぐ
def add_item(self, name, price):
self._items.append({"name": name, "price": price})
@property
def subtotal(self):
return sum(item["price"] for item in self._items)
@property
def tax(self):
return self.subtotal * self._tax_rate
@property
def total(self):
return self.subtotal + self.tax
cart = ShoppingCart()
cart.add_item("商品A", 1000)
cart.add_item("商品B", 2000)
print(f"小計: {cart.subtotal}円")
print(f"税額: {cart.tax}円")
print(f"合計: {cart.total}円")
読み取り専用・書き込み専用プロパティ
読み取り専用プロパティ
import datetime
class Order:
def __init__(self):
self._created_at = datetime.datetime.now()
self._status = "pending"
@property
def created_at(self): # getterのみ(読み取り専用)
return self._created_at
@property
def order_id(self):
return f"ORDER_{self._created_at.strftime('%Y%m%d_%H%M%S')}"
@property
def status(self):
return self._status
@status.setter
def status(self, value):
allowed_statuses = ["pending", "confirmed", "shipped", "delivered"]
if value in allowed_statuses:
self._status = value
order = Order()
print(order.order_id) # ORDER_20241129_143022
# order.created_at = datetime.datetime.now() # エラー:setterがない
書き込み専用プロパティ
import hashlib
class UserAccount:
def __init__(self):
self._password_hash = ""
@property
def password(self):
raise AttributeError("パスワードは読み取れません")
@password.setter
def password(self, value): # setterのみ(書き込み専用)
# パスワードをハッシュ化して保存
self._password_hash = hashlib.sha256(value.encode()).hexdigest()
def verify_password(self, password):
hash_to_check = hashlib.sha256(password.encode()).hexdigest()
return hash_to_check == self._password_hash
user = UserAccount()
user.password = "secret123" # 設定可能
# print(user.password) # エラー:getterがない
print(user.verify_password("secret123")) # True
高度なgetter・setterパターン
1. 遅延初期化(Lazy Initialization)
class DataProcessor:
def __init__(self):
self._data = None
self._processed_data = None
@property
def processed_data(self):
if self._processed_data is None:
print("データを処理中...")
self._processed_data = self._process_data()
return self._processed_data
def _process_data(self):
# 重い処理をシミュレート
return [x * 2 for x in range(1000)]
processor = DataProcessor()
# 最初のアクセス時のみ処理が実行される
data1 = processor.processed_data # "データを処理中..."が出力
data2 = processor.processed_data # 処理済みデータを返す
2. オブザーバーパターン
class Observable:
def __init__(self):
self._value = 0
self._observers = []
def add_observer(self, callback):
self._observers.append(callback)
@property
def value(self):
return self._value
@value.setter
def value(self, new_value):
old_value = self._value
self._value = new_value
# 値が変更されたら全オブザーバーに通知
for callback in self._observers:
callback(old_value, new_value)
def on_value_changed(old, new):
print(f"値が {old} から {new} に変更されました")
observable = Observable()
observable.add_observer(on_value_changed)
observable.value = 10 # "値が 0 から 10 に変更されました"
3. デコレータを使った自動キャッシュ
def cached_property(func):
def wrapper(self):
cache_name = f"_cached_{func.__name__}"
if not hasattr(self, cache_name):
setattr(self, cache_name, func(self))
return getattr(self, cache_name)
return property(wrapper)
class ExpensiveCalculation:
def __init__(self, data):
self.data = data
@cached_property
def result(self):
print("重い計算を実行中...")
return sum(x**2 for x in self.data)
calc = ExpensiveCalculation(range(1000))
print(calc.result) # 重い計算が実行される
print(calc.result) # キャッシュされた結果を返す
パフォーマンス考慮事項
getter・setterのオーバーヘッド
import time
class DirectAccess:
def __init__(self):
self.value = 0
class PropertyAccess:
def __init__(self):
self._value = 0
@property
def value(self):
return self._value
@value.setter
def value(self, val):
self._value = val
# パフォーマンステスト
def benchmark_access():
direct = DirectAccess()
prop = PropertyAccess()
# 直接アクセス
start = time.time()
for i in range(100000):
direct.value = i
_ = direct.value
direct_time = time.time() - start
# プロパティアクセス
start = time.time()
for i in range(100000):
prop.value = i
_ = prop.value
prop_time = time.time() - start
print(f"直接アクセス: {direct_time:.4f}秒")
print(f"プロパティ: {prop_time:.4f}秒")
よくある間違いと対処法
1. 無限再帰の回避
# ❌ 無限再帰になる例
class BadExample:
@property
def value(self):
return self.value # 自分自身を呼び出してしまう
@value.setter
def value(self, val):
self.value = val # 同じく無限再帰
# ✅ 正しい実装
class GoodExample:
def __init__(self):
self._value = 0
@property
def value(self):
return self._value # プライベート属性を返す
@value.setter
def value(self, val):
self._value = val # プライベート属性に設定
2. 適切な命名規則
class StyleGuide:
def __init__(self):
self._internal_value = 0 # プライベート属性
self.__very_private = 0 # より強いプライベート
@property
def public_value(self): # パブリックプロパティ
return self._internal_value
@public_value.setter
def public_value(self, value):
if isinstance(value, int):
self._internal_value = value
実務でのベストプラクティス
1. 段階的なgetter・setter導入
# Phase 1: 単純なクラス
class User:
def __init__(self, name, email):
self.name = name
self.email = email
# Phase 2: バリデーションが必要になったらgetter・setterを追加
class ValidatedUser:
def __init__(self, name, email):
self.name = name # setterが呼ばれる
self.email = email # setterが呼ばれる
@property
def name(self):
return self._name
@name.setter
def name(self, value):
if len(value.strip()) > 0:
self._name = value.strip()
else:
raise ValueError("名前は空にできません")
@property
def email(self):
return self._email
@email.setter
def email(self, value):
if "@" in value:
self._email = value.lower()
else:
raise ValueError("有効なメールアドレスが必要です")
2. APIとの統合
class APIResponse:
def __init__(self, data):
self._raw_data = data
@property
def user_name(self):
return self._raw_data.get("user", {}).get("name", "不明")
@property
def is_success(self):
return self._raw_data.get("status") == "success"
@property
def formatted_date(self):
from datetime import datetime
timestamp = self._raw_data.get("timestamp")
if timestamp:
return datetime.fromtimestamp(timestamp).strftime("%Y-%m-%d")
return None
# 使用例
api_data = {
"status": "success",
"user": {"name": "太郎"},
"timestamp": 1640995200
}
response = APIResponse(api_data)
print(response.user_name) # "太郎"
print(response.formatted_date) # "2022-01-01"
まとめ:getter・setterマスターのポイント
getter・setterの利点
- データの安全性確保
- バリデーション機能
- 計算プロパティの実現
- 後方互換性の維持
適切な使用場面
- データの入力検証が必要
- 計算結果を動的に提供
- アクセス制御が必要
- 外部APIとのインターフェース
避けるべき落とし穴
- 無意味なgetter・setterの濫用
- 無限再帰の発生
- パフォーマンスへの過度な影響
- 複雑すぎるロジックの実装
設計の原則
- 必要な時にのみ実装
- シンプルで理解しやすい構造
- 適切な命名規則の使用
- テストしやすい設計
getter・setterをマスターすることで、より安全で保守性の高いオブジェクト指向プログラムが書けるようになります。まずは基本的なバリデーションから始めて、徐々に高度なパターンを身につけていきましょう。
■プロンプトだけでオリジナルアプリを開発・公開してみた!!
■AI時代の第一歩!「AI駆動開発コース」はじめました!
テックジム東京本校で先行開始。
■テックジム東京本校
「武田塾」のプログラミング版といえば「テックジム」。
講義動画なし、教科書なし。「進捗管理とコーチング」で効率学習。
より早く、より安く、しかも対面型のプログラミングスクールです。
<短期講習>5日で5万円の「Pythonミニキャンプ」開催中。
<月1開催>放送作家による映像ディレクター養成講座
<オンライン無料>ゼロから始めるPython爆速講座


