pythonクラス属性のアクセス、設定、削除

49366 ワード

クラス属性とオブジェクト属性
クラスに定義された属性をクラス属性と呼びます.このクラスのすべてのオブジェクトはクラス属性を共有し、クラス属性は継承性があり、クラスに動的にクラス属性を追加することができます.
オブジェクトは作成後に追加のプロパティを追加することもできます.このプロパティをオブジェクトプロパティと呼びます.オブジェクトプロパティはそのオブジェクトにのみ属し、継承性はありません.
クラス属性とオブジェクト属性は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つに分けられます.
  • オブジェクト(インスタンス)を介してプロパティにアクセス、設定、削除します.すなわち、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と呼ばれます.
    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]は、属性アクセスに関連するメソッドであり、優先度は次のとおりです.
  • クラスで定義されている場合_getattribute__メソッドの場合、__が呼び出されます.getattribute__.
  • アクセス属性が存在する場合、2.1 属性はDescriptorで、この属性を呼び出す_です.get__ 2.2 プロパティがDescriptorでない場合は、__が呼び出されます.dict__[attr]
  • クラスに属性が定義されていない場合は、__が呼び出されます.getattr__
  • それ以外の場合、異常AttributeError
  • を放出する
    検証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とは逆です.
  • クラスで定義されている場合_setattr__メソッドでは、直接__を呼び出します.setattr__
  • 割り当てられた属性がDescriptorである場合、2.1 このDescriptorで定義されている_set__,ダイレクトコール_set__2.2  このDescriptorには定義がありません_set__,呼び出し_dict__[attr]=val
  • 割り当てられた属性がDescriptorでない場合は、直接__を呼び出します.dict__[attr]=val
  • 属性が存在しない場合は、その属性を動的に追加して__を呼び出すdict__[attr]=valによる付与
  •  
    検証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と同じです.
  • クラスで定義されている場合_delattr__メソッドでは、直接__を呼び出します.delattr__
  • 割り当てられた属性がDescriptorであり、Descriptorに定義されている場合delete__,ダイレクトコール_delete__
  • 割り当てられた属性がDescriptorであり、Descriptorに定義されていない場合delete__,異常が報告されますAttributeError:属性は読み取り専用の
  • です.
  • 割り当てられた属性がDescriptorでない場合、例外AttributeErrorも報告されます.属性は読み取り専用の
  • です.
  • この属性が存在しない場合、異常を報告するAttributeError
  •  検証5
    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を使用して属性にアクセスするルールは、次のとおりです.
  • 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
  • が放出される