国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Python > 正文

淺談python類屬性的訪問、設置和刪除方法

2019-11-25 16:37:50
字體:
來源:轉載
供稿:網友

類屬性和對象屬性

我們把定義在類中的屬性稱為類屬性,該類的所有對象共享類屬性,類屬性具有繼承性,可以為類動態地添加類屬性。

對象在創建完成后還可以為它添加額外的屬性,我們把這部分屬性稱為對象屬性,對象屬性僅屬于該對象,不具有繼承性。

類屬性和對象屬性都會被包含在dir()中,而vars()是僅包含對象屬性。vars()跟__dict__是等同的。

類屬性和對象屬性可類比于Java中的static成員和非static成員,只不python中的類屬性和對象屬性都是可以動態添加(和刪除)的。

class A(object):  name='orisun'  def __init__(self):    self.age=10class B(A):  city='bei jing'  def __init__(self):    self.tempurature=20if __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=10if __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']zcyzcyzcytom

下文中討論的全部是類屬性,不涉及對象屬性。

對屬性的訪問、設置和刪除又分為2種情況:

1.通過對象(實例)訪問、設置和刪除屬性,即obj.attr、obj.attr=val、del obj.attr

2.通過類訪問、設置和刪除屬性,即Cls.attr、Cls.attr=val、del Cls.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]都是跟屬性訪問相關的方法,它們的優先級:

1.當類中定義了__getattribute__方法時,則調用__getattribute__。

2.如果訪問的屬性存在,且

2.1  屬性是個Descriptor,是調用這個屬性的__get__

2.2 屬性不是Descriptor,則調用__dict__[attr]

3.如果類中沒有定義該屬性,則調用__getattr__

4.否則,拋出異常AttributeError 

驗證4

class A(object):  passif __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正好反過來:

1.如果類中定義了__setattr__方法,則直接調用__setattr__

2.如果賦值的屬性是個Descriptor,且

2.1  該Descriptor中定義了__set__,則直接調用__set__

2.2  該Descriptor中沒有定義__set__,則調用__dict__[attr]=val

3.如果賦值的屬性不是Descriptor,則直接調用__dict__[attr]=val

4.如果該屬性不存在,則動態地添加該屬性,然后調用__dict__[attr]=val進行賦值

驗證4

class A(object):  passif __name__ == '__main__':  a=A()  a.d='hello'  print a.d

輸出:

hello

驗證3

class A(object):  d=10if __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):    passclass 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雷同。

1.如果類中定義了__delattr__方法,則直接調用__delattr__

2.如果賦值的屬性是個Descriptor,且該Descriptor中定義了__delete__,則直接調用__delete__

3.如果賦值的屬性是個Descriptor,且該Descriptor中沒有定義__delete__,則會報異常AttributeError:屬性是只讀的

4.如果賦值的屬性不是Descriptor,也會報異常AttributeError:屬性是只讀的

5.如果該屬性不存在,則報異常AttributeError

驗證5

class A(object):  passif __name__ == '__main__':  a=A()  del a.d

輸出

AttributeError: 'A' object has no attribute 'd'

驗證4

class A(object):  d=10if __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訪問屬性的規則為:

1.如果MetaClass中有__getattribute__,則直接返回該__getattribute__的結果。

2.如果attr是個Descriptor,則直接返回Descriptor的__get__的結果。

3.如果attr是通過屬性,則直接返回attr的值

4.如果類中沒有attr,且MetaClass中定義了__getattr__,則調用MetaClass中的__getattr__

5.如果類中沒有attr,且MetaClass中沒有定義__getattr__,則拋出異常AttributeError

通過類設置屬性

通過A.attr=val給屬性賦值時:

1.如果MetaClass中定義了__setattr__,則執行該__setattr__

2.如果該屬性是Descriptor,且定義了__set__,則執行Descriptor的__set__

3.如果是普通屬性或None-data Descriptor,則直接令attr=val

4.如果屬性不存在,則動態給類添加該屬性,然后進行賦值

通過類刪除屬性

通過del A.attr刪除屬性時:

1.如果MetaClass中定義了__delattr__,則執行該__delattr__

2.如果該屬性是Descriptor,且定義了__delete__,則執行Descriptor的__delete__

3.如果是普通屬性,或雖是Descriptor但是沒有定義__delete__,則直接從A.__dict__中刪除該屬性

4.如果屬性不存在,則拋出異常AttributeError

以上這篇淺談python類屬性的訪問、設置和刪除方法就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 二连浩特市| 句容市| 定边县| 田东县| 彰武县| 额敏县| 汶上县| 吉木萨尔县| 五大连池市| 朝阳县| 连州市| 宁陵县| 敦化市| 突泉县| 江陵县| 新余市| 南岸区| 平乐县| 汾阳市| 太湖县| 温州市| 台前县| 中阳县| 岳阳县| 新沂市| 嘉善县| 琼结县| 忻州市| 长汀县| 丰城市| 大冶市| 绵竹市| 泸西县| 南溪县| 阿荣旗| 筠连县| 登封市| 天祝| 灵璧县| 益阳市| 昌邑市|