pythonクラス属性のアクセス、設定、削除
49366 ワード
クラス属性とオブジェクト属性
クラスに定義された属性をクラス属性と呼びます.このクラスのすべてのオブジェクトはクラス属性を共有し、クラス属性は継承性があり、クラスに動的にクラス属性を追加することができます.
オブジェクトは作成後に追加のプロパティを追加することもできます.このプロパティをオブジェクトプロパティと呼びます.オブジェクトプロパティはそのオブジェクトにのみ属し、継承性はありません.
クラス属性とオブジェクト属性はdir()に含まれ、vars()はオブジェクト属性のみが含まれます.vars()と_dict__同等です.
クラス属性とオブジェクト属性はJavaのstaticメンバーと非staticメンバーに類比でき、pythonのクラス属性とオブジェクト属性だけが動的に追加(削除)できます.
しゅつりょく
クラスにクラス属性を動的に追加すると、クラスのすべてのオブジェクトにその属性が追加されます(クラス属性を動的に追加する前に作成されたオブジェクトであっても).インスタンスによってプロパティを変更しても、他のインスタンスの同名プロパティとクラスの同名プロパティには影響しません.
しゅつりょく
以下で説明するのはすべてクラス属性であり、オブジェクト属性には触れません.
プロパティへのアクセス、設定、削除は、次の2つに分けられます.オブジェクト(インスタンス)を介してプロパティにアクセス、設定、削除します.すなわち、obj.attr、obj.attr=val、del obj.attr です.クラスを介してプロパティにアクセス、設定、削除します.すなわち、Class.attr、Class.attr=val、del Class.attr です.
本稿では,この2つのケースについてそれぞれ議論する.
Descriptor
ひとつのDescriptorは実現したことを指します_get__のクラス、実装_set__および_delete__オプションです.同時に実現したget__および_set__Data Descriptorと呼ばれています.get__Non-data Descriptorと呼ばれます.
まずDescriptorの例をあげます.get__、__set__、__delete__の役割はあとで詳しく話します.
インスタンスによるプロパティへのアクセス
__getattribute__、__getattr__、__get__および_dict__[attr]は、属性アクセスに関連するメソッドであり、優先度は次のとおりです.クラスで定義されている場合_getattribute__メソッドの場合、__が呼び出されます.getattribute__. アクセス属性が存在する場合、2.1 属性はDescriptorで、この属性を呼び出す_です.get__ 2.2 プロパティがDescriptorでない場合は、__が呼び出されます.dict__[attr] クラスに属性が定義されていない場合は、__が呼び出されます.getattr__ それ以外の場合、異常AttributeError を放出する
検証4
出力:
検証3
出力:
検証2.1
出力:
__getattr__呼び出されていません.
検証2.2
出力:
__getattr__呼び出されていません.
検証1
出力:
__get__および_getattr__呼び出されていません.
インスタンスによるプロパティの設定
属性設定に関するメソッドは3つあります.setattr__、__set__および_dict__[attr]=val.優先順位はgetとは逆です.クラスで定義されている場合_setattr__メソッドでは、直接__を呼び出します.setattr__ 割り当てられた属性がDescriptorである場合、2.1 このDescriptorで定義されている_set__,ダイレクトコール_set__2.2 このDescriptorには定義がありません_set__,呼び出し_dict__[attr]=val 割り当てられた属性がDescriptorでない場合は、直接__を呼び出します.dict__[attr]=val 属性が存在しない場合は、その属性を動的に追加して__を呼び出すdict__[attr]=valによる付与
検証4
出力:
検証3
出力:
検証2.2
出力:
検証2.1
しゅつりょく
コード「a.d=30」が呼び出されたので_set__,そして_set__何もしていないので、属性dはDescriptorオブジェクト(30ではなく)で、「print a.d」を実行すると自然に_get__
検証1
しゅつりょく
呼び出しました_setattr__,そして_set__転勤はされていません.
インスタンスによる属性の削除
del instance.attrを呼び出して属性削除を行うと、__に移動する可能性があります.delattr__または_delete__,それらの優先度はsetと同じです.クラスで定義されている場合_delattr__メソッドでは、直接__を呼び出します.delattr__ 割り当てられた属性がDescriptorであり、Descriptorに定義されている場合delete__,ダイレクトコール_delete__ 割り当てられた属性がDescriptorであり、Descriptorに定義されていない場合delete__,異常が報告されますAttributeError:属性は読み取り専用の です.割り当てられた属性がDescriptorでない場合、例外AttributeErrorも報告されます.属性は読み取り専用の です.この属性が存在しない場合、異常を報告するAttributeError 検証5
しゅつりょく
検証4
しゅつりょく
検証3
しゅつりょく
検証2
しゅつりょく
検証1
しゅつりょく
__delete__呼び出されていません.
__get__ __set__ __delete__パラメータの説明
しゅつりょく
3つのメソッドパラメータのobjはDescriptor属性が存在するオブジェクトであり、ownerパラメータ(_get__のownerパラメータ)はそのオブジェクトが属するクラスであることがわかる.
上記の説明では、インスタンス操作プロパティについて説明します.「インスタンスをクラスに変換し、クラスをMetaClassに変換する」という変換を行うと、クラス操作プロパティのルールになります.この対応する変換も分かりやすく、クラスはオブジェクトを作成するために使用され、MetaClassはクラスを作成するために使用されます.
クラスによるプロパティへのアクセス
A.attrを使用して属性にアクセスするルールは、次のとおりです. MetaClassに__がある場合getattribute__,そのまま_を返すgetattribute__と入力します. attrがDescriptorの場合、Descriptorの_に直接戻ります.get__と入力します. attrが属性を通過する場合、attrの値 が直接返される.クラスにattrがない場合、MetaClassで__が定義されています.getattr__,MetaClassの_を呼び出します.getattr__ クラスにattrがない場合、MetaClassに定義されていない_getattr__,異常を放出するAttributeError クラスによる属性の設定
A.attr=valで属性に値を割り当てる場合: MetaClassで定義されている場合_setattr__,すると、この__が実行されるsetattr__ 属性がDescriptorであり、__が定義されている場合set__,Descriptorの_を実行します.set__ 通常属性またはNone-data Descriptorの場合、attr=val に直接属性が存在しない場合、クラスに動的に属性を追加し、 を割り当てる.
クラスによる属性の削除
del A.attrで属性を削除する場合: MetaClassで定義されている場合_delattr__,すると、この__が実行されるdelattr__ 属性がDescriptorであり、__が定義されている場合delete__,Descriptorの_を実行します.delete__ 通常属性の場合、またはDescriptorであるが定義されていない_delete__,そのままA._からdict__で削除する属性 属性が存在しない場合、例外AttributeError が放出される
クラスに定義された属性をクラス属性と呼びます.このクラスのすべてのオブジェクトはクラス属性を共有し、クラス属性は継承性があり、クラスに動的にクラス属性を追加することができます.
オブジェクトは作成後に追加のプロパティを追加することもできます.このプロパティをオブジェクトプロパティと呼びます.オブジェクトプロパティはそのオブジェクトにのみ属し、継承性はありません.
クラス属性とオブジェクト属性はdir()に含まれ、vars()はオブジェクト属性のみが含まれます.vars()と_dict__同等です.
クラス属性とオブジェクト属性はJavaのstaticメンバーと非staticメンバーに類比でき、pythonのクラス属性とオブジェクト属性だけが動的に追加(削除)できます.
class A(object):
name='orisun'
def __init__(self):
self.age=10
class B(A):
city='bei jing'
def __init__(self):
self.tempurature=20
if __name__ == '__main__':
a=A()
print dir(A)
print dir(a)
print a.__dict__
print vars(a)
print
b=B()
print dir(B)
print dir(b)
print b.__dict__
print vars(b)
しゅつりょく
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'name']
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'name']
{'age': 10}
{'age': 10}
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'city', 'name']
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'city', 'name', 'tempurature']
{'tempurature': 20}
{'tempurature': 20}
クラスにクラス属性を動的に追加すると、クラスのすべてのオブジェクトにその属性が追加されます(クラス属性を動的に追加する前に作成されたオブジェクトであっても).インスタンスによってプロパティを変更しても、他のインスタンスの同名プロパティとクラスの同名プロパティには影響しません.
class A(object):
name='orisun'
def __init__(self):
self.age=10
if __name__ == '__main__':
a=A()
print dir(a)
A.city='BeiJing' # ,
b=A()
A.name='zcy' # ,
print dir(b)
print dir(a)
print a.name
b.name='tom' # ,
print a.name
print A.name
print b.name
しゅつりょく
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'name']
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'city', 'name']
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'city', 'name']
zcy
zcy
zcy
tom
以下で説明するのはすべてクラス属性であり、オブジェクト属性には触れません.
プロパティへのアクセス、設定、削除は、次の2つに分けられます.
本稿では,この2つのケースについてそれぞれ議論する.
Descriptor
ひとつのDescriptorは実現したことを指します_get__のクラス、実装_set__および_delete__オプションです.同時に実現したget__および_set__Data Descriptorと呼ばれています.get__Non-data Descriptorと呼ばれます.
class Descriptor(object):
def __get__(self,instance,owner):
return 'Descriptor in '+owner.__name__
def __set__(self,obj,val):
pass
def __delete__(self,obj):
pass
まずDescriptorの例をあげます.get__、__set__、__delete__の役割はあとで詳しく話します.
インスタンスによるプロパティへのアクセス
__getattribute__、__getattr__、__get__および_dict__[attr]は、属性アクセスに関連するメソッドであり、優先度は次のとおりです.
検証4
class A(object):
pass
if __name__ == '__main__':
a=A()
print a.d
出力:
AttributeError: 'A' object has no attribute 'd'
検証3
class A(object):
def __getattr__(self,name):
return name+" not found in "+self.__class__.__name__+" object"
if __name__ == '__main__':
a=A()
print a.d
出力:
d not found in A object
検証2.1
class Descriptor(object):
def __get__(self,instance,owner):
return 'Descriptor in '+owner.__name__
class A(object):
d=Descriptor()
def __getattr__(self,name):
return name+" not found in "+self.__class__.__name__+" object"
if __name__ == '__main__':
a=A()
print a.d
出力:
Descriptor in A
__getattr__呼び出されていません.
検証2.2
class A(object):
d=10
def __getattr__(self,name):
return name+" not found in "+self.__class__.__name__+" object"
if __name__ == '__main__':
a=A()
print a.d
出力:
10
__getattr__呼び出されていません.
検証1
class Descriptor(object):
def __get__(self,instance,owner):
return 'Descriptor in '+owner.__name__
class A(object):
d=Descriptor()
def __getattribute__(self,name):
return '__getattribute__ '
def __getattr__(self,name):
return name+" not found in "+self.__class__.__name__+" object"
if __name__ == '__main__':
a=A()
出力:
__getattribute__
__get__および_getattr__呼び出されていません.
インスタンスによるプロパティの設定
属性設定に関するメソッドは3つあります.setattr__、__set__および_dict__[attr]=val.優先順位はgetとは逆です.
検証4
class A(object):
pass
if __name__ == '__main__':
a=A()
a.d='hello'
print a.d
出力:
hello
検証3
class A(object):
d=10
if __name__ == '__main__':
a=A()
a.d=30
print a.d
出力:
30
検証2.2
class Descriptor(object):
def __get__(self,instance,owner):
return 'Descriptor in '+owner.__name__
class A(object):
d=Descriptor()
if __name__ == '__main__':
a=A()
a.d=30
print a.d
出力:
30
検証2.1
class Descriptor(object):
def __get__(self,instance,owner):
return 'Descriptor in '+owner.__name__
def __set__(self,instance,value):
pass
class A(object):
d=Descriptor()
if __name__ == '__main__':
a=A()
a.d=30
print a.d
しゅつりょく
Descriptor in A
コード「a.d=30」が呼び出されたので_set__,そして_set__何もしていないので、属性dはDescriptorオブジェクト(30ではなく)で、「print a.d」を実行すると自然に_get__
検証1
class Descriptor(object):
def __get__(self,instance,owner):
return 'Descriptor in '+owner.__name__
def __set__(self,instance,value):
print '__set__'
class A(object):
d=Descriptor()
def __setattr__(self,name,value):
print '__setattr__'
if __name__ == '__main__':
a=A()
a.d=30
print a.d
しゅつりょく
__setattr__
Descriptor in A
呼び出しました_setattr__,そして_set__転勤はされていません.
インスタンスによる属性の削除
del instance.attrを呼び出して属性削除を行うと、__に移動する可能性があります.delattr__または_delete__,それらの優先度はsetと同じです.
class A(object):
pass
if __name__ == '__main__':
a=A()
del a.d
しゅつりょく
AttributeError: 'A' object has no attribute 'd'
検証4
class A(object):
d=10
if __name__ == '__main__':
a=A()
del a.d
しゅつりょく
AttributeError: 'A' object attribute 'd' is read-only
検証3
class Descriptor(object):
def __get__(self,instance,owner):
return 'Descriptor in '+owner.__name__
class A(object):
d=Descriptor()
if __name__ == '__main__':
a=A()
del a.d
しゅつりょく
AttributeError: 'A' object attribute 'd' is read-only
検証2
class Descriptor(object):
def __get__(self,instance,owner):
return 'Descriptor in '+owner.__name__
def __delete__(self,instance):
print '__delete__'
class A(object):
d=Descriptor()
if __name__ == '__main__':
a=A()
del a.d
しゅつりょく
__delete__
検証1
class Descriptor(object):
def __get__(self,instance,owner):
return 'Descriptor in '+owner.__name__
def __delete__(self,instance):
print '__delete__'
class A(object):
d=Descriptor()
def __delattr__(self,name):
print '__delattr__'
if __name__ == '__main__':
a=A()
del a.d
しゅつりょく
__delattr__
__delete__呼び出されていません.
__get__ __set__ __delete__パラメータの説明
class Descriptor(object):
def __get__(self,obj,owner):
return '__get__',self,obj,owner
def __set__(self,obj,val):
print '__set__',self,obj,val
def __delete__(self,obj):
print '__delete__',self,obj
class A(object):
d=Descriptor()
if __name__ == '__main__':
a=A()
print a.d
a.d=3
del a.d
しゅつりょく
('__get__', <__main__.Descriptor object at 0x100481c10>, <__main__.A object at 0x1004a0fd0>, <class '__main__.A'>)
__set__ <__main__.Descriptor object at 0x100481c10> <__main__.A object at 0x1004a0fd0> 3
__delete__ <__main__.Descriptor object at 0x100481c10> <__main__.A object at 0x1004a0fd0>
3つのメソッドパラメータのobjはDescriptor属性が存在するオブジェクトであり、ownerパラメータ(_get__のownerパラメータ)はそのオブジェクトが属するクラスであることがわかる.
上記の説明では、インスタンス操作プロパティについて説明します.「インスタンスをクラスに変換し、クラスをMetaClassに変換する」という変換を行うと、クラス操作プロパティのルールになります.この対応する変換も分かりやすく、クラスはオブジェクトを作成するために使用され、MetaClassはクラスを作成するために使用されます.
class MetaClass(object):
pass
class A(object):
__metaclass__=MetaClass
クラスによるプロパティへのアクセス
A.attrを使用して属性にアクセスするルールは、次のとおりです.
A.attr=valで属性に値を割り当てる場合:
クラスによる属性の削除
del A.attrで属性を削除する場合: