クラスとインスタンス
コンストラクタとデストラクタ
コンストラクタとは何か
コンストラクタ(__init__
メソッド)とは、クラスのインスタンスが生成される際に自動的に実行される特殊なメソッドです。これを使って、オブジェクトの初期化(属性の設定など)を行います。
コンストラクタの特徴:
-
__init__
という名前で定義される。 -
インスタンスが作成されたときに1度だけ実行される。
-
self
を使ってインスタンスの属性を定義する。
デストラクタとは何か
デストラクタ(__del__
メソッド)とは、オブジェクトが削除される際に自動的に実行される特殊なメソッドです。これを使って、リソースの解放や後処理を行うことができます。
デストラクタの特徴:
-
__del__
という名前で定義される。 -
インスタンスが削除される際に自動的に呼び出される。
-
print
などを用いて、オブジェクトが削除されるタイミングを確認できる。
標準的なコンストラクタとデストラクタの書き方
class Sample:
def __init__(self, name):
self.name = name
print(f"{self.name} が生成されました")
def __del__(self):
print(f"{self.name} が削除されました")
obj = Sample("Object1")
del obj # 明示的に削除
このコードでは:
-
__init__
メソッドでname
を初期化し、オブジェクトの生成時にメッセージを出力。 -
__del__
メソッドで、オブジェクトの削除時にメッセージを出力。 -
del obj
によってobj
を削除し、デストラクタが実行されることを確認。
このように、コンストラクタとデストラクタを使うことで、オブジェクトのライフサイクルを管理できます。
クラスメンバーとインスタンスメンバー
クラスメンバーとは何か
クラスメンバーとは、クラス全体で共有される変数やメソッドのことです。クラスのすべてのインスタンスで共通の値を持ちます。クラスメンバーは、self
を使わず、クラス名を使って定義します。
クラスメンバーの特徴:
-
すべてのインスタンスで共有される。
-
self
ではなくクラス名.変数
でアクセスする。 -
クラスメソッドやスタティックメソッドと併用されることが多い。
インスタンスメンバーとは何か
インスタンスメンバーとは、各インスタンスごとに異なる値を持つ変数やメソッドのことです。インスタンスを作成すると、それぞれのオブジェクトが独自のデータを持つことができます。
インスタンスメンバーの特徴:
-
各インスタンスごとに異なる値を持つ。
-
self.変数名
の形で定義する。 -
self
を使ってアクセスする。
クラスメンバーとインスタンスメンバーの標準的な書き方
class Sample:
class_variable = "クラスメンバー" # クラスメンバー
def __init__(self, value):
self.instance_variable = value # インスタンスメンバー
# インスタンスの作成
obj1 = Sample("インスタンス1のデータ")
obj2 = Sample("インスタンス2のデータ")
print(Sample.class_variable) # クラスメンバーの表示
print(obj1.instance_variable) # obj1のインスタンスメンバー
print(obj2.instance_variable) # obj2のインスタンスメンバー
このコードでは:
-
class_variable
はMyClass
のクラスメンバーであり、すべてのインスタンスで共有される。 -
__init__
メソッドでself.instance_variable
を定義し、各インスタンスが独自の値を持つようにしている。 -
MyClass.class_variable
は0
のまま変わらない(クラス全体で共有)。 -
obj1.instance_variable
は10
、obj2.instance_variable
は20
となる(インスタンスごとに異なる)。
このように、クラスメンバーとインスタンスメンバーを適切に使い分けることで、プログラムをより効率的に管理できます。
継承とオーバーライド
継承とは何か
継承とは、既存のクラス(親クラスまたはスーパークラス)の機能を引き継いで、新しいクラス(子クラスまたはサブクラス)を作成する仕組みです。継承を利用することで、コードの再利用性を高め、共通の処理を親クラスにまとめることができます。
継承のメリット
-
コードの再利用:既存のクラスの機能を再利用できるため、新たにコードを書く必要が減る。
-
メンテナンス性の向上:共通の機能を親クラスにまとめることで、一箇所の修正で済む。
-
階層構造の構築:関連するクラスを整理し、論理的なクラス設計ができる。
継承の標準的な書き方
Pythonでは、クラス定義時に括弧内に親クラスを指定することで継承を実現できます。
class 親クラス:
def __init__(self, 引数):
self.属性 = 引数
def 親クラスのメソッド(self):
print("親クラスのメソッド")
# 子クラスが親クラスを継承
class 子クラス(親クラス):
def 子クラスのメソッド(self):
print("子クラスのメソッド")
ポイント
-
子クラス(親クラス)
のように、子クラスの定義時に親クラスを指定する。 -
親クラスのメソッドや属性をそのまま使用できる。
-
必要に応じて、新しいメソッドを追加したり、オーバーライド(上書き)したりできる。
継承の具体例
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
print("動物は音を出します")
# Animalを継承したDogクラス
class Dog(Animal):
def speak(self):
print(f"{self.name} はワンワンと鳴く")
dog = Dog("ポチ")
dog.speak() # ポチ はワンワンと鳴く
この例では、Dog
クラスが Animal
クラスを継承しています。Animal
クラスの name
属性を利用しつつ、speak()
メソッドをオーバーライドしています。
オーバーライドとは何か
オーバーライド(Override)とは、親クラスのメソッドを子クラスで上書きすることです。継承したメソッドの動作を変更したい場合に使用します。
オーバーライドの特徴
-
親クラスと同じ名前のメソッド を子クラスで再定義する。
-
親クラスのメソッドの動作を変更することができる。
オーバーライドの具体例
class Parent:
def greet(self):
print("こんにちは、親クラスです")
class Child(Parent):
def greet(self):
print("こんにちは、子クラスです")
obj = Child()
obj.greet() # こんにちは、子クラスです
この例では、Parent
クラスの greet()
メソッドが Child
クラスでオーバーライドされています。Child
のインスタンスで greet()
を呼び出すと、親クラスの greet()
ではなく、子クラスで定義した greet()
が実行されます。
super() を使った親クラスのメソッド呼び出し
オーバーライドしたメソッド内で、親クラスのメソッドを呼び出すには super()
を使用します。
class Parent:
def greet(self):
print("こんにちは、親クラスです")
class Child(Parent):
def greet(self):
super().greet() # 親クラスの greet() を呼び出し
print("そして、子クラスです")
obj = Child()
obj.greet()
実行結果
こんにちは、親クラスです
そして、子クラスです
super().greet()
によって、まず親クラスの greet()
が実行され、その後に子クラスの print()
文が実行されます。
カプセル化とプロパティ(@property)
カプセル化とは何か
カプセル化とは、クラス内部のデータ(属性)を直接外部から変更できないようにし、適切なメソッドを通じてのみアクセスできるようにする仕組みです。
これにより、データの不正な変更を防ぎ、安全で管理しやすいコードを実現できます。
カプセル化のメリット
-
データの保護: 直接アクセスを防ぎ、意図しない変更を防止できる。
-
データの管理が容易: 外部からの操作を制限し、データの整合性を保つ。
-
プログラムの柔軟性向上: 必要に応じてアクセス制御を変更できる。
Pythonでは、属性名の前にアンダースコア _
やダブルアンダースコア __
をつけることで、アクセス制限を示します。
カプセル化の書き方
class Person:
def __init__(self, name, age):
self.name = name # パブリック属性(制限なし)
self.__age = age # プライベート属性(外部から直接アクセス不可)
def get_age(self): # 年齢を取得するためのメソッド
return self.__age
def set_age(self, age): # 年齢を更新するためのメソッド
if age > 0:
self.__age = age
else:
print("年齢は正の値でなければなりません")
person = Person("太郎", 25)
print(person.name) # OK: "太郎"
print(person.get_age()) # OK: 25
# print(person.__age) # エラー: '__age' は外部からアクセスできない
person.set_age(30) # 年齢を更新
print(person.get_age()) # OK: 30
ポイント
-
self.__age
のように、属性名を__
で始めると「プライベート変数」となり、外部から直接アクセスできない。 -
get_age()
やset_age()
のようなメソッドを使い、制御された方法でデータを取得・変更する。
プロパティ(@property)とは何か
@property
デコレーターを使うことで、ゲッター(値を取得するメソッド)とセッター(値を設定するメソッド)を定義し、通常の属性のようにアクセスできるようになります。
これにより、内部のデータをカプセル化しつつ、より直感的にデータを扱うことができます。
プロパティを使うメリット
-
メソッドのように制御しつつ、属性のように扱える
-
外部からのアクセスを簡単にしつつ、内部のデータを保護できる
-
後から内部実装を変更しても、外部コードに影響を与えにくい
@property を使った書き方
class Person:
def __init__(self, name, age):
self.name = name
self.__age = age # プライベート属性
@property
def age(self): # age を取得するプロパティ
return self.__age
@age.setter
def age(self, value): # age を設定するプロパティ
if value > 0:
self.__age = value
else:
print("年齢は正の値でなければなりません")
person = Person("太郎", 25)
print(person.age) # OK: 25 (ゲッターが呼ばれる)
person.age = 30 # OK: セッターが呼ばれる
print(person.age) # OK: 30
person.age = -5 # NG: "年齢は正の値でなければなりません"
ポイント
-
@property
を使うと、person.age
のように通常の属性のようにアクセスできる。 -
@age.setter
を使うと、person.age = 値
のように代入できるが、内部的にはset_age()
のような処理を実行できる。
クラスメソッド・スタティックメソッド
クラスメソッドとは何か
クラスメソッドとは、クラス全体に関係するメソッドで、インスタンスではなくクラスに対して操作を行うものです。
通常のメソッドとは異なり、最初の引数として self
ではなく cls
を受け取ります。@classmethod
デコレーターを使用して定義し、クラス変数の操作やクラスの設定を行う際に便利です。
クラスメソッドの特徴
-
クラスに対して操作を行う(インスタンスごとではなく、クラス全体で共有される)。
-
cls
を第一引数として受け取る(cls
はクラス自体を指す)。 -
クラス変数を操作できる。
クラスメソッドの書き方
class Car:
manufacturer = "Toyota" # クラス変数(すべてのインスタンスで共有される)
def __init__(self, model):
self.model = model # インスタンス変数
@classmethod
def set_manufacturer(cls, name): # クラスメソッド
cls.manufacturer = name # クラス変数を変更
@classmethod
def get_manufacturer(cls): # クラスメソッド
return cls.manufacturer
# クラスメソッドを呼び出し
print(Car.get_manufacturer()) # Toyota
Car.set_manufacturer("Honda") # クラス変数を変更
print(Car.get_manufacturer()) # Honda
car1 = Car("Corolla")
print(car1.manufacturer) # Honda(変更が反映される)
ポイント
-
@classmethod
をつけることで、通常のインスタンスメソッドとは異なり、クラス全体を操作できる。 -
cls.manufacturer
のように、クラス変数を直接変更可能。 -
クラス名
Car.get_manufacturer()
のように、インスタンスを作成しなくてもメソッドを呼び出せる。
スタティックメソッドとは何か
スタティックメソッドとは、クラスやインスタンスのデータには依存せず、独立した処理を行うメソッドです。
第一引数として self
や cls
を受け取らず、通常の関数のように動作します。@staticmethod
デコレーターを使用して定義します。
スタティックメソッドの特徴
-
クラスやインスタンスの属性を参照しない。
-
汎用的な処理をまとめるために使う(例えば、計算処理や補助的な処理)。
-
インスタンス化せずに呼び出せる。
スタティックメソッドの書き方
class MathUtil:
@staticmethod
def add(a, b):
return a + b
@staticmethod
def multiply(a, b):
return a * b
# インスタンス化せずに呼び出し
print(MathUtil.add(10, 5)) # 15
print(MathUtil.multiply(4, 3)) # 12
ポイント
-
@staticmethod
をつけることで、クラスやインスタンスに依存しない独立したメソッドを作成できる。 -
クラス名
MathUtil.add(10, 5)
のように直接呼び出せる。
クラスメソッドとスタティックメソッドの違い
メソッドの種類 | 目的 | 第一引数 | クラス変数の変更 | インスタンス変数の使用 |
---|---|---|---|---|
通常のメソッド | インスタンスのデータを操作 | self |
可能 | 可能 |
クラスメソッド | クラス全体のデータを操作 | cls |
可能 | 不可 |
スタティックメソッド | 独立した処理を行う | なし | 不可 | 不可 |
以上、クラスとオブジェクト指向についての説明でした。次の章では、例外処理について学びます。