Python黑魔法@property裝飾器的使用技巧解析
@property有什么用呢?表面看來(lái),就是將一個(gè)方法用屬性的方式來(lái)訪問(wèn).
上代碼,代碼最清晰了.
class Circle(object):
def __init__(self, radius):
self.radius = radius
@property
def area(self):
return 3.14 * self.radius ** 2
c = Circle(4)
print c.radius
print c.area
可以看到,area雖然是定義成一個(gè)方法的形式,但是加上@property后,可以直接c.area,當(dāng)成屬性訪問(wèn).
現(xiàn)在問(wèn)題來(lái)了,(不是挖掘機(jī)技術(shù)哪家強(qiáng)),每次調(diào)用c.area,都會(huì)計(jì)算一次,太浪費(fèi)cpu了,怎樣才能只計(jì)算一次呢?這就是lazy property.
class lazy(object):
def __init__(self, func):
self.func = func
def __get__(self, instance, cls):
val = self.func(instance)
setattr(instance, self.func.__name__, val)
return val
class Circle(object):
def __init__(self, radius):
self.radius = radius
@lazy
def area(self):
print 'evalute'
return 3.14 * self.radius ** 2
c = Circle(4)
print c.radius
print c.area
print c.area
print c.area
可以看到,'evalute'只輸出了一次.如果看了我前面幾篇博文,對(duì)@lazy的機(jī)制應(yīng)該很好理解.
在這里,lazy類(lèi)有__get__方法,說(shuō)明是個(gè)描述器,第一次執(zhí)行c.area的時(shí)候,因?yàn)轫樞騿?wèn)題,先去c.__dict__中找,沒(méi)找到,就去類(lèi)空間找,在類(lèi)Circle中,有area()方法,于是就被__get__攔截.
在__get__中,調(diào)用實(shí)例的area()方法算出結(jié)果,并動(dòng)態(tài)給實(shí)例添加個(gè)同名屬性把結(jié)果賦給它,即加到c.__dict__中去.
再次執(zhí)行c.area的時(shí)候,先去c.__dict__找,因?yàn)榇藭r(shí)已經(jīng)有了,就不會(huì)經(jīng)過(guò)area()方法和__get__了.
注意點(diǎn)
請(qǐng)注意以下代碼場(chǎng)景:
代碼片段1:
Python2.6代碼
class Parrot(object):
def __init__(self):
self._voltage = 100000
@property
def voltage(self):
"""Get the current voltage."""
return self._voltage
if __name__ == "__main__":
# instance
p = Parrot()
# similarly invoke "getter" via @property
print p.voltage
# update, similarly invoke "setter"
p.voltage = 12
代碼片段2:
Python2.6代碼
class Parrot:
def __init__(self):
self._voltage = 100000
@property
def voltage(self):
"""Get the current voltage."""
return self._voltage
if __name__ == "__main__":
# instance
p = Parrot()
# similarly invoke "getter" via @property
print p.voltage
# update, similarly invoke "setter"
p.voltage = 12
代碼1、2的區(qū)別在于
class Parrot(object):
在python2.6下,分別運(yùn)行測(cè)試
片段1:將會(huì)提示一個(gè)預(yù)期的錯(cuò)誤信息 AttributeError: can't set attribute
片段2:正確運(yùn)行
參考python2.6文檔,@property將提供一個(gè)ready-only property,以上代碼沒(méi)有提供對(duì)應(yīng)的@voltage.setter,按理說(shuō)片段2代碼將提示運(yùn)行錯(cuò)誤,在python2.6文檔中,我們可以找到以下信息:
BIF:
property([fget[, fset[, fdel[, doc]]]])
Return a property attribute for new-style classes (classes that derive from object).
原來(lái)在python2.6下,內(nèi)置類(lèi)型 object 并不是默認(rèn)的基類(lèi),如果在定義類(lèi)時(shí),沒(méi)有明確說(shuō)明的話(huà)(代碼片段2),我們定義的Parrot(代碼片段2)將不會(huì)繼承object
而object類(lèi)正好提供了我們需要的@property功能,在文檔中我們可以查到如下信息:
new-style class
Any class which inherits from object. This includes all built-in types like list and dict. Only new-style classes can use Python's newer, versatile features like __slots__, descriptors, properties, and __getattribute__().
同時(shí)我們也可以通過(guò)以下方法來(lái)驗(yàn)證
Python 2.6代碼
class A: pass >>type(A) <type 'classobj'>
Python 2.6代碼
class A(object): pass >>type(A) <type 'type'>
從返回的<type 'classobj'>,<type 'type'>可以看出<type 'type'>是我們需要的object類(lèi)型(python 3.0 將object類(lèi)作為默認(rèn)基類(lèi),所以都將返回<type 'type'>)
為了考慮代碼的python 版本過(guò)渡期的兼容性問(wèn)題,我覺(jué)得應(yīng)該定義class文件的時(shí)候,都應(yīng)該顯式定義object,做為一個(gè)好習(xí)慣
最后的代碼將如下:
class Parrot(object):
def __init__(self):
self._voltage = 100000
@property
def voltage(self):
"""Get the current voltage."""
return self._voltage
@voltage.setter
def voltage(self, new_value):
self._voltage = new_value
if __name__ == "__main__":
# instance
p = Parrot()
# similarly invoke "getter" via @property
print p.voltage
# update, similarly invoke "setter"
p.voltage = 12
另外,@property是在2.6、3.0新增的,2.5沒(méi)有該功能。
相關(guān)文章
Python實(shí)現(xiàn)繁體轉(zhuǎn)為簡(jiǎn)體的方法示例
這篇文章主要介紹了Python實(shí)現(xiàn)繁體轉(zhuǎn)為簡(jiǎn)體的方法,涉及Python編碼轉(zhuǎn)換相關(guān)操作技巧,需要的朋友可以參考下2018-12-12
Python機(jī)器學(xué)習(xí)NLP自然語(yǔ)言處理基本操作之命名實(shí)例提取
自然語(yǔ)言處理(?Natural?Language?Processing,?NLP)是計(jì)算機(jī)科學(xué)領(lǐng)域與人工智能領(lǐng)域中的一個(gè)重要方向。它研究能實(shí)現(xiàn)人與計(jì)算機(jī)之間用自然語(yǔ)言進(jìn)行有效通信的各種理論和方法2021-11-11
Python request post上傳文件常見(jiàn)要點(diǎn)
這篇文章主要介紹了Python request post上傳文件常見(jiàn)要點(diǎn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11
Python實(shí)現(xiàn)在圖像中隱藏二維碼的方法詳解
隱寫(xiě)是一種類(lèi)似于加密卻又不同于加密的技術(shù)。這篇文章主要介紹了如何利用Python語(yǔ)言實(shí)現(xiàn)在圖像中隱藏二維碼功能,感興趣的可以了解一下2022-09-09
django使用channels實(shí)現(xiàn)通信的示例
這篇文章主要介紹了django使用channels實(shí)現(xiàn)通信的示例,幫助大家更好的理解和學(xué)習(xí)django框架,感興趣的朋友可以了解下2020-10-10
Pytest單元測(cè)試框架如何實(shí)現(xiàn)參數(shù)化
這篇文章主要介紹了Pytest單元測(cè)試框架如何實(shí)現(xiàn)參數(shù)化,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09
python requests.post帶head和body的實(shí)例
今天小編就為大家分享一篇python requests.post帶head和body的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-01-01
如何利用pytesseract識(shí)別圖片中的數(shù)字
這篇文章主要介紹了如何利用pytesseract識(shí)別圖片中的數(shù)字問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-05-05
python多進(jìn)程提取處理大量文本的關(guān)鍵詞方法
今天小編就為大家分享一篇python多進(jìn)程提取處理大量文本的關(guān)鍵詞方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-06-06

