python@property装饰器的原理,@property装饰器的作用

  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:

  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

代码1、2的区别在于

  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):

  pass

  >>type(A)

  <type'type'>

从返回的<type 'classobj'>,<type 'type'>可以看出<type 'type'>是我们需要的object类型(python 3.0 将object类作为默认基类,所以都将返回<type 'type'>)

  为了考虑代码的python 版本过渡期的兼容性问题,我觉得应该定义class文件的时候,都应该显式定义object,做为一个好习惯

  最后的代码将如下

  

classParrot(object):

  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

另外,@property是在2.6、3.0新增的,2.5没有该功能。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: