原文:https://zhuanlan.zhihu.com/p/32764345html
# 相似函数的形式 class A: def __init__(self, name, score): self.name = name # 普通属性 self.score = score def getscore(self): return self._score def setscore(self, value): print('setting score here') if isinstance(value, int): self._score = value else: print('please input an int') score = property(getscore, setscore) a = A('Bob',90) a.name # 'Bob' a.score # 90 a.score = 'bob' # please input an int
分析上述调用score的过程python
property(getscore, setscore)
对象,由于后者中定义了__get__
与__set__
方法,所以是一个资料描述器,具备比属性更高的优先级,因此这里就访问了描述器__set__
方法__set__
中对fset
属性进行检查,这里即传入的setscore
,不是None
,因此调用了fset
即setscore
方法,这就实现了设置属性时使用自定义函数进行检查的目的__get__
也是同样,查询score时,调用__get__
方法,触发了getscore
方法下面是另外一种使用property的方法缓存
# 装饰器形式,即引言中的形式 class A: def __init__(self, name, score): self.name = name # 普通属性 self.score = score @property def score(self): print('getting score here') return self._score @score.setter def score(self, value): print('setting score here') if isinstance(value, int): self._score = value else: print('please input an int') a = A('Bob',90) # a.name # 'Bob' # a.score # 90 # a.score = 'bob' # please input an int
下面进行分析框架
score
时,加上装饰器变成访问property(score)
这个描述器,这个score
也做为fget
参数传入__get__
中指定调用时的操做setter
等方法的定义property
和setter
装饰器的两个方法的命名都仍是score,通常同名的方法后面的会覆盖前面的,因此调用时调用的是后面的setter
装饰器处理过的score
,是以若是两个装饰器定义的位置调换,将没法进行属性赋值操做。setter
装饰器的score
时,面临一个问题,装饰器score.setter
是什么呢?是score
的setter
方法,而score
是什么呢,不是下面定义的这个score
,由于那个score
只至关于参数传入。自动向其余位置寻找有没有现成的score
,发现了一个,是property
修饰过的score
,这是个描述器,根据property
的定义,里面确实有一个setter
方法,返回的是property
类传入fset
后的结果,仍是一个描述器,这个描述器传入了fget
和fset
,这就是最新的score
了,之后实例只要调用或修改score
,使用的都是这个描述器del
则装饰器中的score
找到的是setter
处理过的score
,最新的score
就会是三个函数都传入的score
score
的调用及赋值删除都跟前面同样了property
的原理就讲到这里,从它的定义咱们能够知道它其实就是将咱们设置的检查等函数传入get set
等方法中,让咱们能够自由对属性进行操做。它是一个框架,让咱们能够方便传入其余操做,当不少对象都要进行相同操做的话,重复就是不免的。若是想要避免重复,只有本身写一个相似property
的框架,这个框架不是传入咱们但愿的操做了,而是就把这些操做放在框架里面,这个框架由于只能实现一种操做而不具备普适性,可是却能大大减小当前问题代码重复问题ide
下面使用描述器定义了Checkint类以后,会发现A类简洁了很是多函数
class Checkint: def __init__(self, name): self.name = name def __get__(self, instance, owner): if instance is None: return self else: return instance.__dict__[self.name] def __set__(self, instance, value): if isinstance(value, int): instance.__dict__[self.name] = value else: print('please input an integer') # 相似函数的形式 class A: score = Checkint('score') age = Checkint('age') def __init__(self, name, score, age): self.name = name # 普通属性 self.score = score self.age = age a = A('Bob', 90, 30) a.name # 'Bob' a.score # 90 # a.score = 'bob' # please input an int # a.age='a' # please input an integer
由于我本人也刚刚学描述器不久,对它的应用还不是很是了解,下面只列举我如今能想到的它有什么用,之后若是想到其余的再补充ui
__get__
方法中,在判断语句下,obj.__dict__[self.name] = value
。这样每次再调用这个方法都会从这个字典中取得值,而不是从新运行这个方法。(例子来源最后的那个例子)参考网页以下spa