日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > python >内容正文

python

python getattr和getattribute_python中__getattr__和__getattribute__区别

發(fā)布時間:2023/12/19 python 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python getattr和getattribute_python中__getattr__和__getattribute__区别 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

重載__getattr__方法對類及其實例未定義的屬性有效。如果訪問的屬性存在,就不會調(diào)用__getattr__方法。這個屬性的存在,包括類屬性和實例屬性

classClassA:

x= 'a'

def __init__(self):

self.y= 'b'

def __getattr__(self, item):return '__getattr__'

if __name__ == '__main__':

a=ClassA()print(a.x)#輸出結(jié)果 a

#使用實例直接訪問實例存在的屬性時,不會調(diào)用__getattr__方法

print(a.y) #輸出結(jié)果 b

#使用實例直接訪問實例不存在的屬性時,會調(diào)用__getattr__方法

print(a.z) #輸出結(jié)果 __getattr__

__getattribute__僅在新式類中可用,重載__getattrbute__方法對類實例的每個屬性訪問都有效,無論屬性存不存在都會先調(diào)用__getattribute__方法

classClassA:

x= 'a'

def __init__(self):

self.y= 'b'

def __getattribute__(self, item):return '__getattribute__'

if __name__ == '__main__':

a=ClassA()#使用實例直接訪問存在的類屬性時,會調(diào)用__getattribute__方法

print(a.x) #輸出結(jié)果 __getattribute__

#使用實例直接訪問實例存在的實例屬性時,會調(diào)用__getattribute__方法

print(a.y) #輸出結(jié)果 __getattribute__

#使用實例直接訪問實例不存在的實例屬性時,也會調(diào)用__getattribute__方法

print(a.z) #輸出結(jié)果 __getattribute__

當(dāng)同時定義__getattribute__和__getattr__時,__getattr__方法不會再被調(diào)用,除非顯示調(diào)用__getattr__方法或引發(fā)AttributeError異常。

classClassA:def __getattr__(self, item):print('__getattr__')def __getattribute__(self, item):print('__getatttribute__')if __name__ == '__main__':

a=ClassA()

a.x

運行結(jié)果__getatttribute__

由于__getattr__只針對未定義屬性的調(diào)用,所以它可以在自己的代碼中自由地獲取其他屬性,

而__getattribute__針對所有的屬性運行,因此要十分注意避免在訪問其他屬性時,再次調(diào)用自身的遞歸循環(huán)。死循環(huán)!!

當(dāng)在__getattribute__代碼塊中,再次執(zhí)行屬性的獲取操作時,會再次觸發(fā)__getattribute__方法的調(diào)用,代碼將會陷入無限遞歸,直到Python遞歸深度限制(重載__setter__? __setattr__方法也會有這個問題)。

示例代碼(無限遞歸):

classClassA:

x= 'a'

def __getattribute__(self, item):print('__getattribute__')return self.item #再次出現(xiàn)屬性的獲取操作,會再次觸發(fā)__getattribute__的調(diào)用

#相當(dāng)于return self.__getattribute__(item)

if __name__ == '__main__':

a=ClassA()

a.x

運行結(jié)果,達(dá)到最大遞歸深度

ecursionError: maximum recursion depth exceeded

也沒辦法通過從__dict__取值的方式來避免無限遞歸(重寫__setattr__可以通過__dict__取值的方式來避免無限遞歸)

classClassA:

x= 'a'

def __getattribute__(self, name):return self.__dict__[name] #__dict__魔法方法可以查看對象的屬性,返回一個字典,鍵代表屬性名 ,這樣再次出現(xiàn)屬性獲取的操作,會再次觸發(fā)__getattribute__if __name__ == '__main__':

a=ClassA()

a.x#無限遞歸

為了避免無限遞歸,應(yīng)該把獲取屬性的方法?__getattribute__指向一個更高的超類,例如object(因為__getattribute__只在新式類中可用,而新式類所有的類都顯式或隱式地繼承自object,所以對于新式類來說,object是所有新式類的超類)。利用super()方法

classClassA:

x= 'a'   #類屬性

def __getattribute__(self, item):print('__getattribute__')return super().__getattribute__(self, item)if __name__ == '__main__':

a=ClassA()print(a.x) #輸出__getattribute__

a

調(diào)用__getattr__詳細(xì)過程如下:

obj.attribute

首先會在對象的實例屬性中尋找,找不到執(zhí)行第二步

來到對象所在的類中查找類屬性,如果還找不到執(zhí)行第三步

來到對象的繼承鏈上尋找,如果還找不到執(zhí)行第四步

調(diào)用obj.__getattr__方法,如果用戶沒有定義或者還是找不到,拋出AttributeError異常,屬性查找失敗

classMyClass:def __init__(self, x):

self.x=x>>> obj = MyClass(1)>>>obj.y

AttributeError:'MyClass' object has no attribute 'a'

如上代碼,沒有定義__getattr__魔法方法,又找不到屬性,就會拋出異常

調(diào)用__getattrIbute__方法

當(dāng)我們調(diào)用對象的屬性時,首先會調(diào)用__getattribute__魔法方法。無論對象存不存在;當(dāng)__getattribute__查找失敗,就會去調(diào)用__getattr__方法。

obj.x

obj.__getattribute__(x)

這兩個代碼其實是等價的

使用__getattribute__魔法方法時,要返回父類的方法,(super函數(shù))不然很難寫對!!會導(dǎo)致無限遞歸!

另外,內(nèi)置的bif? ?getattr和hasattr也會觸發(fā)這個魔法方法__getattribute__!!

其他細(xì)節(jié)需要注意

1.  _getattribute__的查找順序

classMyClass:

x= 999         #類屬性x

def __init__(self, x):   #形參x

self.x=x       #實例屬性xdef __getattribute__(self, item):print('正在獲取屬性{}'.format(item))return super(MyClass, self).__getattribute__(item)

>>> obj = MyClass(2)

>>> print(obj.x)

正在獲取屬性x

2

>>> del obj.x     #刪除了實例屬性x

>>> print(obj.x)   #此時訪問的是類屬性

正在獲取屬性

999

上面代碼中,定義了一個類屬性x和一個實例屬性x,這兩個屬性同名,根據(jù)Python語法規(guī)則,當(dāng)對象獲取屬性x的時候,首先會在實例屬性中尋找,如果找不到才回去類屬性中查找

這便是__getattribute__的查找順序。通常該方法在框架中可能會用到,一般情況下無需使用

2.  super 對象沒有 __getattr__魔法方法!!

>>> classC:def __getattr__(self, name):print(1)return super().__getattr__(name)def __getattribute__(self, name):print(2)return super().__getattribute__(name)def __setattr__(self, name, value):print(3)

super().__setattr__(name, value)def __delattr__(self, name):print(4)

super().__delattr__(name)>>> c =C()>>>c.x

運行結(jié)果:>>> c =C()>>>c.x2

1Traceback (most recent call last):

File"", line 1, in c.x

File"", line 4, in __getattr__

return super().__getattr__(name)

AttributeError:'super' object has no attribute '__getattr__'

分析一下:首先 c.x 會先調(diào)用 __getattribute__() 魔法方法,打印 2;然后調(diào)用 super().__getattribute__(),找不到屬性名 x,因此會緊接著調(diào)用 __getattr__() ,于是打印 1;你希望最后以 super().__getattr__() 終了的時候,Python 竟然告訴你 AttributeError,super 對象木有 __getattr__ !

證明:

>>>dir(super)

['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__',

'__gt__', '__hash__', '__init__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',

'__self__', '__self_class__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__thisclass__']

(dir()?函數(shù)不帶參數(shù)時,返回當(dāng)前范圍內(nèi)的變量、方法和定義的類型列表;帶參數(shù)時,返回參數(shù)的屬性、方法列表。如果參數(shù)包含方法__dir__(),該方法將被調(diào)用。如果參數(shù)不包含__dir__(),該方法將最大限度地收集參數(shù)信息)

3.  初學(xué)常犯錯誤沒有“觀前顧后”!

例如:編寫一個 Counter 類,用于實時檢測對象有多少個屬性。

classCounter:def __init__(self):

self.counter=0    # 屬性賦值,這里會觸發(fā) __setattr__ 調(diào)用def __setattr__(self, name, value): #self是綁定的對象,name是屬性名(name必須是字符串),value是為對象屬性賦的值

self.counter+= 1super().__setattr__(name, value) #這時候 self.counter 還沒有定義,所以沒法 += 1,錯誤的根源。def __delattr__(self, name):

self.counter-= 1super().__delattr__(name)

>>>c =Counter()

運行結(jié)果:

AttributeError: 'Counter' object has no attribute 'counter'

正確代碼:

classCounter:def __init__(self):

super().__setattr__('counter', 0)         #調(diào)用基類的賦值魔法方法__setattr__(name,value) name必須是字符串!def __setattr__(self, name, value):

super().__setattr__('counter', self.counter + 1)

super().__setattr__(name, value)def __delattr__(self, name):

super().__setattr__('counter', self.counter - 1)

super().__delattr__(name)

另外的

__setattr__(self, name, value)

定義當(dāng)一個屬性被設(shè)置時的行為

__delattr__(self, name)

定義當(dāng)一個屬性被刪除時的行為

總結(jié)

以上是生活随笔為你收集整理的python getattr和getattribute_python中__getattr__和__getattribute__区别的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。