はじめに
オブジェクト指向プログラミング(OOP)の世界へようこそ!前のレッスンではクラスとインスタンス、コンストラクタ、継承について学びましたね。今回は、OOPの重要な概念である「カプセル化」、そしてクラス内でデータを保持する方法である「クラス変数」と「インスタンス変数」について詳しく見ていきましょう。
これらの概念を理解することで、より安全で整理された、再利用しやすいコードを書くことができるようになります 。
1. カプセル化 (Encapsulation)
カプセル化とは、オブジェクトのデータ(属性)とそのデータを操作するメソッド(関数)を一つにまとめ、オブジェクトの内部状態を外部から隠蔽することです。これにより、外部から直接データにアクセスされるのを防ぎ、意図しない変更や不正な操作からデータを保護します。
Pythonでは、アクセス修飾子(のようなもの)を使ってカプセル化を実現します。厳密な意味でのアクセス修飾子(他の言語の `public`, `private`, `protected`)はありませんが、命名規則によってアクセスレベルを示唆します。
- Public (公開): 通常の変数名(例: `name`)。どこからでもアクセス可能です。
- Protected (保護): 変数名の前にアンダースコアを1つ付ける(例: `_name`)。「クラス内とそのサブクラスからアクセスされることを意図している」という慣習的な意味合いを持ちますが、強制力はありません。外部からもアクセスできてしまいます。
- Private (プライベート): 変数名の前にアンダースコアを2つ付ける(例: `__name`)。Pythonが内部的に名前マングリング(名前の改変)を行い、クラス外部からの直接的なアクセスを困難にします。ただし、完全に不可能ではありません。
コード例
プライベート変数 `__private_var` は、外部から直接 `obj.__private_var` としてアクセスしようとするとエラーになります。これはPythonが `_クラス名__変数名`(例: `_MyClass__private_var`)という名前に内部で変換(名前マングリング)するためです。知っていればアクセスできてしまいますが、意図的に隠蔽されていることを示す強力なサインです。
一般的には、プライベート変数へのアクセスや変更が必要な場合は、上記例の `get_private_var` や `set_private_var` のようなゲッター(Getter)やセッター(Setter)と呼ばれる公開メソッドを用意します。これにより、値の取得や設定時にバリデーション(検証)などの追加処理を挟むことができます。
2. クラス変数 (Class Variables)
クラス変数とは、そのクラスの全てのインスタンス間で共有される変数です。クラス定義の直下に記述されます。
コード例
注意点: インスタンス (`hachi`) を使ってクラス変数 (`species`) と同じ名前の属性に値を代入すると、そのインスタンス固有のインスタンス変数が新たに作成されます。元のクラス変数が変更されるわけではありません。クラス変数を変更したい場合は、必ず `クラス名.変数名`(例: `Dog.species`)を使うようにしましょう。
3. インスタンス変数 (Instance Variables)
インスタンス変数とは、それぞれのインスタンスに固有の変数です。通常、`__init__` メソッド内で `self.変数名 = 値` のように定義され、各インスタンスが異なる状態を持つことを可能にします。
コード例
この例では、`make`, `model`, `year`, `color`, `odometer` は全てインスタンス変数です。`car1` と `car2` はそれぞれ異なるメーカー、モデル、年式、色、走行距離を持っています。`drive` メソッドを呼び出すと、そのインスタンスの `odometer` だけが更新されます。
4. クラス変数 vs インスタンス変数 まとめ
クラス変数とインスタンス変数の違いを理解することは、オブジェクト指向設計において非常に重要です。以下に主な違いをまとめます。
特徴 | クラス変数 | インスタンス変数 |
---|---|---|
定義場所 | クラス定義の直下 | 主に `__init__` メソッド内 (self.変数名 ) |
スコープ | クラスとその全てのインスタンスで共有 | 特定のインスタンスのみに属する |
アクセス方法 | クラス名.変数名 または インスタンス名.変数名 |
インスタンス名.変数名 (self.変数名 ) |
変更の影響 | クラス名.変数名 で変更すると、全てのインスタンスに影響 |
変更しても、そのインスタンスにしか影響しない |
主な用途 | 定数、共有設定、インスタンス数のカウントなど | 各インスタンス固有の状態(属性)の保持 |
使い分けの例
この `Circle` クラスでは、円周率 `pi` は全ての円で共通なのでクラス変数として定義し、半径 `radius` は円ごとに異なるのでインスタンス変数として定義しています。これにより、効率的でわかりやすいコードになっています。
まとめ
今回は、オブジェクト指向プログラミングにおける重要な概念である「カプセル化」「クラス変数」「インスタンス変数」について学びました。
- カプセル化は、データを保護し、コードの保守性を高めるためのテクニックです。Pythonでは主に命名規則(`_` や `__`)で表現されます。
- クラス変数は、クラスの全インスタンスで共有されるデータを保持します。
- インスタンス変数は、各インスタンス固有のデータを保持します。
これらの概念を適切に使い分けることで、より堅牢で柔軟なオブジェクト指向プログラムを作成することができます。次のステップに進む前に、これらの違いをしっかり理解しておきましょう!
参考情報
- Python 公式ドキュメント – クラス (特に 9.3.〜9.6.あたりが関連します)