Python, 理解下面这个装饰器(based on class), 有哪几个关键点 ?
问题描述
class memoized_property(object): '''A read-only @property that is only evaluated once.''' def __init__(self, fget, doc=None):self.fget = fgetself.__doc__ = doc or fget.__doc__self.__name__ = fget.__name__ # 这个方法应该是这个缓存装饰器的关键 # 因此, 我组织关键字如下 # * python __get__ # * how python __get__ works # # python descript tools def __get__(self, obj, cls):if obj is None: return selfobj.__dict__[self.__name__] = result = self.fget(obj)return result def _reset(self, obj):memoized_property.reset(obj, self.__name__) @classmethod def reset(cls, obj, name):obj.__dict__.pop(name, None)
问题解答
回答1:根据memoized_property的实现方法,下面的答案都有一个前提,即假设其作为对类函数的装饰器来使用。此时这个类可以看作是property装饰器的修改版。能够实现缓存的效果是因为Python访问属性时是有优先级的。
对于a.val,Python进行如下处理:
先访问对象的__dict__,即a.__dict__[’val’];
如果没有再访问类的A.__dict__[’val’],此时会沿着继承关系一直向上寻找;
如果找到A.__dict__[’val’],返回的是值的话,那么就获得该值;如果返回的是一个描述器,则会调用描述器的__get__方法;
对于这里的memoized_property来说:
比如这个类封装了A类的val函数:
class A(object): ...@memoized_property def val(self):...a = A()a.val
在第一次访问val的时候,根据上面的查找顺序:对象里面没有,跳到第二步;在类的字典里发现了,但发现是描述器,因此会进入到描述器中的__get__方法中。在这里,使用self.fget(obj)调用装饰的val函数并计算结果后,在返回结果的同时,将结果也存储在obj.__dict__[’val’]中。下次再访问a.val的时候,由于对象的__dict__中有val了,就会先查找obj.__dict__[’val’],而不会大动干戈的去找__get__。这样就实现缓存一个属性的效果。而一般的__get__是不会设置obj.__dict__[’xxx’]的,所以每次都是重新计算。
明白了这些以后,reset就很清楚了,只不过把上一个优先级的途径去掉。然后Python就不得不沿着优先级一步步找下去,发现__get__可用,于是又在其中调用a.val方法重新计算了一遍。
而__get__的内部,又能说好多了。。。。
回答2:类方法就是当你不用做类的实例化就可以直接调用的方法
相关文章:
1. 网页爬虫 - Python小白用Scrapy爬虫返回的是空元素,请问各位大神哪里出了问题?2. python - 《flask web 开发》一书,数据库中多对多关系的实现问题?3. python flask做的文件系统上传系统,路径没错,文件列表加载不出来,error 100534. python3.x - 如何在云服务器上运行python脚本?5. curl - Python request 上传文件6. Python爬取网页requests乱码7. python中class里面的self是什么意思?8. python - 求马尔可夫链状态转移概率矩阵9. python - 关于beautifulsoup获取文档内容10. python引用getpass模块输入密码回车后没反应,是在pycharm软件中执行,在python自带的IDE是可以的。
