python基礎文法-6 クラスとオブジェクト指向

python基礎

クラスとインスタンス

コンストラクタとデストラクタ

コンストラクタとは何か

コンストラクタ(__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_variableMyClass のクラスメンバーであり、すべてのインスタンスで共有される。

  • __init__ メソッドで self.instance_variable を定義し、各インスタンスが独自の値を持つようにしている。

  • MyClass.class_variable0 のまま変わらない(クラス全体で共有)。

  • obj1.instance_variable10obj2.instance_variable20 となる(インスタンスごとに異なる)。

このように、クラスメンバーとインスタンスメンバーを適切に使い分けることで、プログラムをより効率的に管理できます。

継承とオーバーライド

継承とは何か

継承とは、既存のクラス(親クラスまたはスーパークラス)の機能を引き継いで、新しいクラス(子クラスまたはサブクラス)を作成する仕組みです。継承を利用することで、コードの再利用性を高め、共通の処理を親クラスにまとめることができます。

継承のメリット

  1. コードの再利用:既存のクラスの機能を再利用できるため、新たにコードを書く必要が減る。

  2. メンテナンス性の向上:共通の機能を親クラスにまとめることで、一箇所の修正で済む。

  3. 階層構造の構築:関連するクラスを整理し、論理的なクラス設計ができる。

継承の標準的な書き方

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)

カプセル化とは何か

カプセル化とは、クラス内部のデータ(属性)を直接外部から変更できないようにし、適切なメソッドを通じてのみアクセスできるようにする仕組みです。
これにより、データの不正な変更を防ぎ、安全で管理しやすいコードを実現できます。

カプセル化のメリット

  1. データの保護: 直接アクセスを防ぎ、意図しない変更を防止できる。

  2. データの管理が容易: 外部からの操作を制限し、データの整合性を保つ。

  3. プログラムの柔軟性向上: 必要に応じてアクセス制御を変更できる。

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 デコレーターを使用して定義し、クラス変数の操作やクラスの設定を行う際に便利です。

クラスメソッドの特徴
  1. クラスに対して操作を行う(インスタンスごとではなく、クラス全体で共有される)。

  2. cls を第一引数として受け取るcls はクラス自体を指す)。

  3. クラス変数を操作できる

クラスメソッドの書き方

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() のように、インスタンスを作成しなくてもメソッドを呼び出せる。

スタティックメソッドとは何か

スタティックメソッドとは、クラスやインスタンスのデータには依存せず、独立した処理を行うメソッドです。
第一引数として selfcls を受け取らず、通常の関数のように動作します。
@staticmethod デコレーターを使用して定義します。

スタティックメソッドの特徴
  1. クラスやインスタンスの属性を参照しない

  2. 汎用的な処理をまとめるために使う(例えば、計算処理や補助的な処理)。

  3. インスタンス化せずに呼び出せる

スタティックメソッドの書き方

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 可能 不可
スタティックメソッド 独立した処理を行う なし 不可 不可

 

 

以上、クラスとオブジェクト指向についての説明でした。次の章では、例外処理について学びます。

error: Content is protected !!
タイトルとURLをコピーしました