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

首頁 > 編程 > Python > 正文

Python黑魔法@property裝飾器的使用技巧解析

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

@property有什么用呢?表面看來,就是將一個方法用屬性的方式來訪問.
上代碼,代碼最清晰了.

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雖然是定義成一個方法的形式,但是加上@property后,可以直接c.area,當成屬性訪問.
現在問題來了,(不是挖掘機技術哪家強),每次調用c.area,都會計算一次,太浪費cpu了,怎樣才能只計算一次呢?這就是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'只輸出了一次.如果看了我前面幾篇博文,對@lazy的機制應該很好理解.
在這里,lazy類有__get__方法,說明是個描述器,第一次執行c.area的時候,因為順序問題,先去c.__dict__中找,沒找到,就去類空間找,在類Circle中,有area()方法,于是就被__get__攔截.
在__get__中,調用實例的area()方法算出結果,并動態給實例添加個同名屬性把結果賦給它,即加到c.__dict__中去.
再次執行c.area的時候,先去c.__dict__找,因為此時已經有了,就不會經過area()方法和__get__了.

注意點
請注意以下代碼場景:

代碼片段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的區別在于

class Parrot(object): 

在python2.6下,分別運行測試
片段1:將會提示一個預期的錯誤信息 AttributeError: can't set attribute
片段2:正確運行

參考python2.6文檔,@property將提供一個ready-only property,以上代碼沒有提供對應的@voltage.setter,按理說片段2代碼將提示運行錯誤,在python2.6文檔中,我們可以找到以下信息:

BIF:
property([fget[, fset[, fdel[, doc]]]])
Return a property attribute for new-style classes (classes that derive from object).
原來在python2.6下,內置類型 object 并不是默認的基類,如果在定義類時,沒有明確說明的話(代碼片段2),我們定義的Parrot(代碼片段2)將不會繼承object

而object類正好提供了我們需要的@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__().

同時我們也可以通過以下方法來驗證
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類型(python 3.0 將object類作為默認基類,所以都將返回<type 'type'>)

為了考慮代碼的python 版本過渡期的兼容性問題,我覺得應該定義class文件的時候,都應該顯式定義object,做為一個好習慣

最后的代碼將如下:

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沒有該功能。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 庆云县| 苗栗县| 阿拉善右旗| 苍溪县| 双桥区| 西青区| 卓资县| 贺州市| 惠州市| 白河县| 安西县| 呼图壁县| 易门县| 宣化县| 连山| 甘泉县| 全南县| 商水县| 陵川县| 桂东县| 海盐县| 安顺市| 吴堡县| 文化| 东海县| 台山市| 湄潭县| 安岳县| 德江县| 阳西县| 绥芬河市| 勐海县| 嵊泗县| 湄潭县| 绍兴县| 青川县| 平利县| 兴安县| 镇沅| 汽车| 台湾省|