python property方法_Python @property使用的问题?

简单说的话就是你在width的getter和setter当中又访问了width,这是个递归调用,在其他语言当中也是这样的。

===================================================================

展开说的话有必要细说一下property的机制,Python当中取对象属性存在多种不同的机制,property属于descriptor机制,在Python当中是一种重要的机制。大致流程是这样的:

当从obj(类型为MyClass)获取名称为attr的属性(也就是obj.attr)时:

如果有MyClass.__getattribute__定义则使用这个过程替代整个过程,不再进行后面的步骤

首先判断obj.__dict__中是否存在名为attr的属性,如果存在直接返回;否则进入第二步。某些情况下obj没有__dict__则直接进入第二步。

从obj的类型(MyClass)中获取attr属性:如果MyClass.__dict__中存在则直接返回

否则按MyClass.__mro__依次查找基类的__dict__直到存在;如果全都不存在,则调用obj.__getattr__过程(默认抛出AttributeError异常)

获取到的属性值:如果有__get__方法,则返回__get__方法调用的结果(这个就叫做descriptor!)

如果没有则直接返回值

set和delete过程也有相应的descriptor机制,不再赘述。

跟重载__getattr__和__setattr__相比,descriptor机制可以很容易改变某几个属性的属性访问机制,而不影响其他属性。

有一些非常重要的功能是通过descriptor实现的,有一些比property更重要也更常用,比如说我们调用类的方法的时候:

class T(object):

def f(self):

return 1

t = T()

t.f()

T.f(t) #等价的

使用t.f的时候不需要再指定第一个参数self的值,这就是因为使用了descriptor机制,T.f(在Python2中是unboundmethod,在Python3中是标准的函数)有__get__方法,会将T.f从原来的类型转换成boundmethod,这是一个绑定了第一个参数的函数对象,于是调用时不再需要指定第一个参数。

property也是一样的,首先要知道property本身是个类型,property()是这个类型的构造函数,这个构造函数的原始形式接受(fget, fset, fdel, doc)四个参数,为了方便将property作为decorator使用,所有四个参数都是可选的,这样当作decorator的时候实际是执行了:

width = property(width)

也就是仅仅使用了第一个参数构造了property。返回的property对象带有__get__,__set__和__delete__方法,会调用相应的fget, fset和fdelete。为了方便进一步构造,这个对象带有getter, setter, deleter方法,大致是这样的:

def setter(self, fset):

self.fset = fset

return self

也就是说只是进一步设置了其中的属性然后返回,所以.setter, .deleter都必须使用一致的名字。

了解这个机制之后就可以明白,Python当中的property与其他语言不同,并不是某种特别定制的语法,而是更泛用的descriptor机制的一部分,在任何代码当中调用都会触发这种机制,也包括在property的getter和setter当中调用。这样我们同时也明白了使用obj.__setattr__('width', value)也是不行的,虽然当时看上去好像是成功了,但是会永久改变width这个属性查找时的特性(改由obj.__dict__提供了)。必须占用一个新的属性名,一般我们在Python当中规定_开头的是私有属性,__(两个下划线)开头且不以__结尾的是“强”的私有属性,会被自动重命名为跟类名有关的名字,所以可以用这类名字来做真正存储属性的名字:

class Screen(object):

@property

def width(self):

return self._width

@width.setter

def width(self, input_width):

self._width = input_width

@property

def height(self):

return self._height

@height.setter

def height(self, input_height):

self._height = input_height

@property

def resolution(self):

return self.height * self.width

最后,如果仅仅是设置一个值而不引起其他变化,不要定义property比较好。不要学Java程序员那一套。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值