一般的に言えば、Python では、クラス インスタンス属性のアクセス ルールは比較的直感的です。
ただし、特に C++ や Java プログラマにとっては、あまり直感的ではない部分がまだいくつかあります。
ここで、次の点を理解する必要があります:
1. Python は動的言語であり、どのエンティティも属性を動的に追加または削除できます。
2. クラスはスコープを定義します。
3. クラス インスタンスには、対応するクラスによって定義されるスコープとは異なるスコープも導入されます。
4. クラス インスタンス内の属性を検索する場合は、まずインスタンス自体のスコープ内で検索します。見つからない場合は、次にクラス定義のスコープ内で検索します。
5. クラス インスタンスの属性に値を割り当てると、属性はクラス インスタンスによって定義されたスコープに実際に追加されます (まだ存在しない場合)。で定義されている同じ名前の属性には影響しません。対応するクラス。
上記の点についての理解を深めるために、以下の例を見てみましょう:
class A:
cls_i = 0
cls_j = {}
def __init__(self):
self.instance_i = 0
self.instance_j = {}
ここでは、まずクラス A のインスタンス a を定義し、次にクラス A のスコープとインスタンス a のスコープ内にあるものを確認します:
>>> a = A()
>>> a.__dict__
{'instance_j': {}, 'instance_i': 0}
>>> A.__dict__
{'__init__': , '__module__': '__main__', 'cls_i' : 0, 'cls_j': {}, '__doc__': None}
a のスコープ内にinstance_i とinstance_j があり、A のスコープ内に cls_i と cls_j があることがわかります。
名前検索がどのように行われるかを見てみましょう:
>>> a.cls_i
0
>>> a.instance_i
0
cls_i を探すとき、インスタンス a のスコープは次のとおりです。はそのようなものではなく、A のスコープ内で見つかります。instance_i を検索すると、a のスコープ内で直接見つけることができます。
インスタンス a を通じて cls_i の値を変更しようとするとどうなりますか:
>>> a.cls_i = 1
>>> a.__dict__
{'instance_j': {}, 'cls_i' : 1 、'instance_i': 0}
>>> A.__dict__
{'__init__': 、'__module__': '__main__'、'cls_i': 0、'cls_j': {}、'__doc__': None}
a のスコープに追加の cls_i 属性があり、その値が 1 であることがわかります。同時に、ここでは A のスコープの cls_i 属性の値がまだ 0 であることにも気づきます。インスタンス属性は追加されますが、クラス属性は変更されません。
インスタンス a を介して cls_j のデータを操作するとどうなりますか (cls_j 自体ではないことに注意してください):
>>> a.cls_j['a'] = 'a'
>>> a.__dict__
{'インスタンス_j': {}, 'cls_i': 1, 'instance_i': 0}
>>> A.__dict__
{'__init__': , '__module__': '__main__', 'cls_i': 0, 'cls_j ': {'a': 'a'}, '__doc__': None}
a のスコープは変更されていませんが、cls_j で A のスコープがいくつか変更されていることがわかります。データは変更されています。
インスタンスのスコープの変更は、クラスの他のインスタンスには影響しませんが、クラスのスコープの変更は、以前に作成されたインスタンスを含むクラスのすべてのインスタンスに影響します:
>> > A.cls_k = 0
>>> i.cls_k
0