生成AIと学ぶPython23: カプセル、アクセス修飾子、setter、getter

カプセル化とは

カプセル化とは、データとその操作(つまり、関数やメソッド)を結びつけるオブジェクト指向プログラミングの原則です。
これにより、オブジェクトの内部状態はそのオブジェクト自身のメソッドによってのみ変更され、外部から直接アクセスされることはありません。これは、コードの保守性と信頼性を向上させ、誤った操作によるバグの可能性を減らします。

Pythonでは、アクセス修飾子を使ってカプセル化を実現します。Pythonには次の3つのアクセス修飾子があります:

  1. Public: これはデフォルトの修飾子で、メンバ変数やメソッドが公開され、外部から直接アクセスできることを意味します。例:name

  2. Protected: 名前の前にアンダースコア _ が付いたメンバ変数やメソッドは、そのクラスおよびそのサブクラスからのみアクセスできることを意味します(ただし、これは主に慣習に過ぎず、Pythonは実際にはこれを強制しません)。例:_name

  3. Private: 名前の前にダブルアンダースコア __ が付いたメンバ変数やメソッドは、そのクラスからのみアクセスできることを意味します。Pythonでは、これらのメンバに直接アクセスすると、AttributeErrorが発生します。例:__name

class MyClass:
    def __init__(self):
        self.name = "Public"
        self._name = "Protected"
        self.__name = "Private"

    def access_private_member(self):
        return self.__name

obj = MyClass()
print(obj.name)    # Outputs: Public
print(obj._name)   # Outputs: Protected
print(obj.__name)  # Raises AttributeError: 'MyClass' object has no attribute '__name'
print(obj.access_private_member())  # Outputs: Private

この例では、__nameMyClassのプライベートメンバであり、そのクラスのメソッドからのみアクセスできます。したがって、access_private_memberメソッドを通じて__nameにアクセスすることはできますが、直接アクセスしようとするとエラーが発生します。

setterとgetter

Pythonでは、プロパティの値を取得したり設定したりするために、ゲッター(getter)セッター(setter)メソッドを使用することができます。これらのメソッドは、データのカプセル化を実現するための重要なツールです。

ゲッターとセッターを使用することで、クラスの内部データに直接アクセスする代わりに、メソッドを通じて間接的にアクセスします。これにより、値の検証、エラーチェック、追加のアクションの実行などを行うことができます。

class Person:
    def __init__(self, name):
        self._name = name  # _name is protected

    @property
    def name(self):
        print("Getting name")
        return self._name

    @name.setter
    def name(self, value):
        if isinstance(value, str):
            print("Setting name to " + value)
            self._name = value
        else:
            raise TypeError("Name must be a string.")

このクラスでは、_nameプロパティは保護されており、直接アクセスすることはできません。その代わりに、nameという名前のゲッターとセッターメソッドが提供されています。これらのメソッドは、デコレータを使って定義されており、プロパティを直接アクセスするかのように使うことができます。

person = Person("Alice")
print(person.name)  # Outputs: Getting name\nAlice
person.name = "Bob"  # Outputs: Setting name to Bob
print(person.name)  # Outputs: Getting name\nBob
person.name = 123   # Raises: TypeError: Name must be a string.

このように、Pythonのゲッターとセッターは、クラスの外部からのデータアクセスを管理し、データの整合性を保つための重要な手段です。

setterとgetterのベストプラクティス

Pythonではプロパティのゲッターとセッター以外にもいくつかの特定の目的に使用することができます。

データ検証: セッターは、値を設定する前にその値が妥当であるかどうかを検証するのに役立ちます。たとえば、あるプロパティが特定の範囲の数値であることを保証することができます。
イベントのトリガリング: セッターは、値が変更されたときに特定のアクション(イベント)をトリガーするのに使用できます。たとえば、値が変更されたときにログを記録したり、その他のメソッドを呼び出したりすることができます。
計算済みのプロパティ: ゲッターは、他の値から計算されるプロパティを提供するのに役立ちます。これにより、その値は読み取り専用のプロパティとして外部に公開され、その値は必要に応じて計算されます。

class Circle:
    def __init__(self, radius):
        self._radius = radius

    @property
    def radius(self):
        return self._radius

    @radius.setter
    def radius(self, value):
        if value >= 0:
            self._radius = value
        else:
            raise ValueError("Radius cannot be negative.")

    @property
    def diameter(self):
        return self._radius * 2

    @property
    def area(self):
        return 3.141592653589793 * self._radius ** 2

この例では、Circle クラスは radiusdiameter、および area という3つのプロパティを提供します。radius プロパティはセッターを使用して値が負でないことを保証します。diameterarea は計算されるプロパティであり、ゲッターのみを提供します。

この記事が気に入ったらサポートをしてみませんか?