使用 property 一般有以下两种方式
通过装饰器
class Demo(object): def __init__(self, val): self._x = val # 经过装饰器后,x 为 property对象 @property def x(self): # after some opertation return self._x # 调用 x 的setter方法(一个装饰器) 返回新的 property 对象 @x.setter def x(self, val): self._x = val @x.deleter def x(self): print 'del x'
通过创建 property 的实例
class Demo2(object): def __init__(self, val): self._x = val def getx(self): return self._x def setx(self, val): self._x = val def delx(self): print 'del x' x = property(getx, setx, delx)
下面是一个使用 __get__ __set__
的等价 property 实现 参考自 http://pyzh.readthedocs.io/en/latest/Descriptor-HOW-TO-Guide.html
class Property(object): "Emulate PyProperty_Type() in Objects/descrobject.c" def __init__(self, fget=None, fset=None, fdel=None, doc=None): self.fget = fget self.fset = fset self.fdel = fdel self.__doc__ = doc def __get__(self, obj, objtype=None): if obj is None: return self if self.fget is None: raise AttributeError, "unreadable attribute" return self.fget(obj) def __set__(self, obj, value): if self.fset is None: raise AttributeError, "can't set attribute" self.fset(obj, value) def __delete__(self, obj): if self.fdel is None: raise AttributeError, "can't delete attribute" self.fdel(obj) def setter(self, fset): return type(self)(self.fget, fset, self.fdel, self.__doc__) def deleter(self, fdel): return type(self)(self.fget, self.fset, fdel, self.__doc__)
假如创建了 Demo 类的实例 demo
当调用 demo.x 时, 会调用 Property 的 __get__
方法
此时的参数 obj 为 demo。通过调用注册好的 fget() 来返回 _x
一个奇怪的例子,
class Demo3(object): def __init__(self, val): self._x = val self.x = property(self.getx, self.setx, self.delx) def getx(self): return self._x def setx(self, val): self._x = val def delx(self): print 'del x' demo = Demo3(0) demo.x # <property at 0x7f26e24ae890>
这是因为
demo.x 首先会调用 __getattribute__
方法,在 Demo3 的字典中找 x ,如果 x 定义了 __get__
方法,那么 x. get
(demo, Demo3)
此过程等价于
type(demo).__dict__['x'].__get__(demo, type(demo))
那么我们尝试
demo.x.__get__(demo, type(demo)) TypeError: getx() takes exactly 1 argument (2 given)
这是因为我们通过实例去调用的 property ,那么我们调用 getx
时自然会和 self 绑定,所以这里多传了一个参数
所以这么改改
class Property(object): "Emulate PyProperty_Type() in Objects/descrobject.c" def __init__(self, fget=None, fset=None, fdel=None, doc=None): self.fget = fget self.fset = fset self.fdel = fdel self.__doc__ = doc def __get__(self, obj, objtype=None): if obj is None: return self if self.fget is None: raise AttributeError, "unreadable attribute" # 不需要传 obj return self.fget()
我来评几句
登录后评论已发表评论数()