Select Language

AI Technology Community

7.9、Python読み取り専用属性の設定(2つの方法)

デフォルトでは、インスタンスオブジェクトのすべてのメンバーは読み取りと書き込みが可能です。しかし、時にはいくつかの制限を設けたい場合があります。例えば、読み取りのみで修正できないようにしたり、修正する値が型要件や範囲要件を満たす必要があることを確認したりすることです。

この機能を実現する方法はいくつかあります。ここでは主に、@property修飾子を使用する方法と__setattr__()関数を定義する方法の2つを紹介します。

@property修飾子を使用する

この方法は、@property修飾子を使って特殊な属性を定義します。この属性に対する読み取り操作は、対応する関数を呼び出し、その関数の戻り値を取得することになります。
注意すべきは、この属性に対して書き込み操作を行うことはできないということです。

>>> class Student:                       # クラスを定義
...     version = "1.0"
...     author = "python.cn"
...     def __init__(self, name, gender, age):
...         self.name = name
...         self.gender = gender
...         self._age = age
...     @property                         # ageは属性で、クラスの外部からは読み取り専用
...     def age(self):
...         return self._age
...                                       # クラス定義終了
>>> student_a = Student('alex', 0, 18)
>>> student_a.age                         # 属性の値を取得
18
>>> student_a.age = 12                    # 修正できない
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: can't set attribute

__setattr__()関数を再定義する

もう1つの方法は、__setattr__()関数を定義してチェックすることです。この関数は、メンバー属性に値が割り当てられるときに呼び出されます。この関数には3つのパラメータがあり、1つ目はself、2つ目はメンバー属性名、3つ目は新しい値です。その基本的な定義形式は次の通りです:

def __setattr__(self, attr, val):

すべてのメンバーに対する割り当て操作でこの関数が呼び出されるため、この関数の内部で現在操作している属性名、つまり2つ目のパラメータを判断する必要があります。読み取り専用の属性については、例外を発生させることができます。書き込み可能な属性については、割り当て操作を行う必要があります。

>>> class Student:
...     version = "1.0"
...     author = "python.cn"
...     def __init__(self, name, gender, age):    # 初期化関数
...         self.name = name
...         self.gender = gender
...         self._age = age
...     def __setattr__(self, attr, val):     # __setattr__()を定義
...         if attr == 'age':                 # age属性の場合、例外を発生させる
...             msg = '{}.{} is READ ONLY'.format(type(self).__name__, attr)
...             raise AttributeError(msg)
...         else:
...             self.__dict__[attr] = val     # その他の属性は修正可能
...                                           # クラス定義終了
>>> student_a = Student('alex', 0, 18)        # クラスインスタンスオブジェクトを作成
>>> student_a.age = 21                        # age属性を修正すると、例外が発生
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 11, in __setattr__
AttributeError: Student.age is READ ONLY

クラス属性のセキュリティチェック

読み書きのチェック以外にも、さらに多くのチェックを行うことができます。例えば、ある属性値の範囲をチェックしたり、属性値の型をチェックしたりすることで、ユーザーが提供する入力値が有効であることを保証し、不正なデータがシステムに書き込まれるのを防ぐことができます。

次の例では、年齢属性に対するセキュリティチェックを行い、ユーザーが無効な年齢データを入力できないようにしています。

>>> class Student:
...     version = "1.0"
...     author = "python.cn"
...     def info():
...         print("version %s, author: %s" % (Student.version, Student.
        author))
...     def __init__(self, name, gender, age):
...         self.name = name
...         self.gender = gender
...         self._age = age
...     def get_age(self):
...         return self._age
...     def set_age(self, new_age):   # age属性に対する書き込み操作時の処理関数
...         if new_age > 40 or new_age < 14:
...             print("invalid age value")
...             return None
...         self._age = new_age
...         return new_age
...     age = property(get_age, set_age)
...                                    # クラス定義終了
>>> student_a = Student('alex', 0, 18) # インスタンスオブジェクトを作成
>>> student_a.age                      # 属性値を読み取る
18
>>> student_a.age = 32                 # 属性を設定
>>> student_a.age
32


もう1つの使い方は次の通りです。

>>> class Student:                 # クラスを定義
...     version = "1.0"
...     author = "python.cn"
...     def info():
...         print("version %s, author: %s" % (Student.version, Student.
        author))
...     def __init__(self, name, gender, age):
...         self.name = name
...         self.gender = gender
...         self._age = age
...     @property
...     def age(self):
...         return self._age
...     @age.setter                 # age属性の設定関数を定義
...     def age(self, val):
...         if val > 40 or val < 14:
...             print("Invalid age")
...             return self._age
...         self._age = val        # クラス定義終了
>>> student_a = Student('alex', 0, 18)
>>> student_a.age
18
>>> student_a.age = 10
Invalid age
>>> student_a.age = 22
>>> student_a.age
22


post
  • 10

    item of content
前の章では、リストや辞書などのPythonの予め定義されたデータ型について説明しました。しかし、自分で新しいタイプを定義したい場合、クラスを使用する必要があります。つまり、クラスを使用することで自分だけのデータ型を定義でき、システムで定義された型だけを使う以上のことができます。
クラスはオブジェクト指向プログラミングにおいて非常に基本的な概念であり、最も基本的な機能は新しいデータ型を作成することです。さらに、クラスAから新しいクラスBを派生させることができ、その際クラスBはクラスAのすべての属性を継承します(これを継承機能と呼びます)。
この章では、クラスの定義と使用方法について説明します。具体的には、クラスのプロパティとメソッド、クラスの派生方法、多重継承の使用方法などを解説します。