python@property装饰器的原理,@property装饰器的作用
@property Decorator可以把一个方法变成一个属性并调用它。我们来看看Python黑魔法@property Decorator的技巧。
@property有什么用?表面上看,是将一个方法作为属性来访问。
上,代码是最清晰的。
classCircle(对象):
def__init__(self,radius):
self.radius=半径
@属性
defarea(self):
return3.14*self.radius**2
c=圆(4)
打印半径
Printc.c.area你可以看到,虽然area被定义为一个方法,但是可以通过添加@property直接作为属性访问。
现在问题来了。每次调用c.area都会计算一次,浪费cpu。怎么能只算一次呢?这是懒惰的财产。
classlazy(object):
def__init__(self,func):
self.func=func
def__get__(self,instance,cls):
val=self.func(实例)
setattr(instance,self.func.__name__,val)
returnval
classCircle(对象):
def__init__(self,radius):
self.radius=半径
@懒
defarea(self):
打印“评估”
return3.14*self.radius**2
c=圆(4)
打印半径
printc.area
printc.area
从printc.area可以看出, evalute 只输出了一次,所以应该对@lazy的机制有很好的理解。
这里,lazy类有__get__方法,这意味着它是一个描述符。第一次执行c.area时,因为顺序问题,先在c. _ _ dict _ _)中找。如果找不到,就在班级空间里找。在类循环中,有area()方法,所以被_ _ get _拦截。
在__get__,调用实例的area()方法计算结果,动态给实例添加一个同名的属性将结果赋给它,即添加到c.__dict__。
再次执行c.area时,先转到c.__dict__,因为此时已经存在,所以不会经过area()方法和__get__。
注意了。
请注意下面的代码场景:
代码片段1:
classParrot(object):
def__init__(self):
nbsp;self._voltage=100000
@property
defvoltage(self):
"""Getthecurrentvoltage."""
returnself._voltage
if__name__=="__main__":
#instance
p=Parrot()
#similarlyinvoke"getter"via@property
printp.voltage
#update,similarlyinvoke"setter"
p.voltage=12代码片段2
classParrot:代码1、2的区别在于def__init__(self):
self._voltage=100000
@property
defvoltage(self):
"""Getthecurrentvoltage."""
returnself._voltage
if__name__=="__main__":
#instance
p=Parrot()
#similarlyinvoke"getter"via@property
printp.voltage
#update,similarlyinvoke"setter"
p.voltage=12
class Parrot(object):
在python2下,分别运行测试
片段1:将会提示一个预期的错误信息 AttributeError: can't set attribute
片段2:正确运行
参考python2文档,@property将提供一个ready-only property,以上代码没有提供对应的@voltage.setter,按理说片段2代码将提示运行错误,在python2文档中,我们可以找到以下信息:
BIF:
property([fget[, fset[, fdel[, doc]]]])
Return a property attribute for new-style classes (classes that derive from object).
原来在python2下,内置类型 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__().
同时我们也可以通过以下方法来验证
classA:pass
>>type(A)
<type'classobj'>
classA(object):从返回的<type 'classobj'>,<type 'type'>可以看出<type 'type'>是我们需要的object类型(python 3.0 将object类作为默认基类,所以都将返回<type 'type'>)pass
>>type(A)
<type'type'>
为了考虑代码的python 版本过渡期的兼容性问题,我觉得应该定义class文件的时候,都应该显式定义object,做为一个好习惯
最后的代码将如下
classParrot(object):另外,@property是在2.6、3.0新增的,2.5没有该功能。def__init__(self):
self._voltage=100000
@property
defvoltage(self):
"""Getthecurrentvoltage."""
returnself._voltage
@voltage.setter
defvoltage(self,new_value):
self._voltage=new_value
if__name__=="__main__":
#instance
p=Parrot()
#similarlyinvoke"getter"via@property
printp.voltage
#update,similarlyinvoke"setter"
p.voltage=12
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。