专栏首页锦小年的博客python学习笔记6.6-类的惰性属性

python学习笔记6.6-类的惰性属性

我们想将一个只读属性定义为property属性方法,只有在访问它时才参与计算。同时,一旦访问了该属性,希望把计算出来的值缓存起来,不要每次访问它时都要重新计算。这样就能很大程度上提升程序的性能。定义一个惰性属性最简单的方法就是利用描述符来完成。

#define a lazyproperty
class Lazyproperty:
    def __init__(self,func):
        self.func = func
    def __get__(self,instance,cls):
        if instance is None:
            return self
        else:
            value = self.func(instance)
            setattr(instance,self.func.__name__,value)
            return value

#Example
import math
class Circle:
    def __init__(self,radius):
        self.radius = radius

    @Lazyproperty
    def area(self):
        print('Computing area')
        return math.pi*self.radius*2
    @Lazyproperty
    def perimeter(self):
        print('Computing perimeter')
        return 2*math.pi*self.radius

c = Circle(4.0)
print(c.radius)
print('calling c.area the first time:')
print(c.area)
print('calling c.area the second time:')
print(c.area)

打印输出:
4.0
calling c.area the first time:
Computing area
25.132741228718345
calling c.area the second time:
25.132741228718345

从示例中可以很清楚的看出,第一次调用c.area时计算过程被执行,第二次调用它的时候,计算过程没有执行,是因为计算一次之后,它的值就被储存起来了,第二次直接拿出来用,从而加快了程序的运行。

前面提到描述符的时候讲过,当吧描述符放到类的定义体中的时候,访问它的属性会出发get(),set(),delete()方法。但是,如果一个描述符只定义了get()方法,则它的绑定关系比一般情况要弱化的多。特别是,只有当被访问的属性不在底层的实例字典中时,_get_()方法会得到调用。

但是,这种技术有一个潜在是bug,一旦使用了这种方法,计算的值就会变成可变的了。

c.area = 66
print(c.area)
打印输出:
66

如果考虑到可变性,可以使用一种方法去修复这个bug,但是同时执行效率也会大大的降低。

def lazyproperty(func):
    name = '_lazy_' + func.__name__
    @property
    def lazy(self):
        if hasattr(self,name):
            return getattr(self,name)
        else:
            value = func(self)
            setattr(self,name,value)
            return value
    return lazy

#Example
import math
class Circle:
    def __init__(self,radius):
        self.radius = radius

    @lazyproperty
    def area(self):
        print('Computing area')
        return math.pi*self.radius*2
    @lazyproperty
    def perimeter(self):
        print('Computing perimeter')
        return 2*math.pi*self.radius

c = Circle(4.0)
print(c.radius)
print('calling c.area the first time:')
print(c.area)
print('calling c.area the second time:')
print(c.area)

打印输出:
4.0
calling c.area the first time:
Computing area
25.132741228718345
calling c.area the second time:
25.132741228718345

从该实例中可以发现,达到了同样的效果。

c.area = 66
print(c.area)

Traceback (most recent call last):
  File "D:/home/WX/test_lazyproperty.py", line 32, in <module>
    c.area = 66
AttributeError: can't set attribute

之后改变c.area的值,发现报错,不能被修改。这样就修复了第一种方法中计算值可以被外部改变的bug。这种方法的缺点就是所有的get操作都必须经由属性的getter函数来处理。这比直接在实例字典中查找相应的值要慢一些。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 实战干货:从零快速搭建自己的爬虫系统

    本文简要归纳了网页爬虫的基础知识,着重于利用现有组件,快速建立一套实际可用的网页爬取、分析系统。系统主要使用Python 作为开发语言,在 Linux 或 Ma...

    胖兔子兔胖
  • 深度学习入门实战(一):像Prisma一样算法生成梵高风格画像

    现在人工智能是个大热点,而人工智能离不开机器学习,机器学习中深度学习又是比较热门的方向,本系列文章就从实战出发,介绍下如何使用MXnet进行深度学习~

    serena
  • 如何轻松爬取网页数据?

    在实际工作中,难免会遇到从网页爬取数据信息的需求,如:从微软官网上爬取最新发布的系统版本。很明显这是个网页爬虫的工作。本文将根据网站特性进行分类介绍几种使用py...

    腾讯移动品质中心TMQ
  • 【腾讯云的1001种玩法】云服务器搭建Python爬虫环境

    在上一篇文章中,我们已经学会了在云服务器上搭建Python环境了,假设你已经在云服务器上搭建好了Python环境,我们将进入下一步:搭建Python爬虫环境。

    钟志远
  • Python 远程控制模块 paramiko 问题解决记录

    生产环境中使用paramiko作SSH远程控制时,发现会有部分机器报Error reading SSH protocol banner错误,尝试使用ssh命令连...

    张戈
  • 腾讯云主机Python3环境安装Scrapy爬虫框架过程及常见错误

    Scrapy安装介绍Scrapy的安装有多种方式,它支持Python2.7版本及以上或Python3.3版本及以上。下面说明Python3环境下的安装过程。Sc...

    崔庆才
  • 反爬虫和抗DDOS攻击技术实践

    企鹅媒体平台媒体名片页反爬虫技术实践,分布式网页爬虫技术、利用人工智能进行人机识别、图像识别码、频率访问控制、利用无头浏览器PhantomJS、Selenium...

    张宁
  • 深度学习入门实战(二):用TensorFlow训练线性回归

    上一篇文章我们介绍了 MxNet 的安装,但 MxNet 有个缺点,那就是文档不太全,用起来可能是要看源代码才能理解某个方法的含义,所以今天我们就介绍一下 Te...

    serena
  • 【腾讯云的1001种玩法】云服务器搭建Python环境

    之前一直在用阿里云服务器跑爬虫、小脚本。这两天在朋友的安利下转到了腾讯云上面来,刚好趁这个机会写一写有关于云服务器上Python爬虫环境的搭建。

    钟志远
  • Django数据处理的一些实践

    提到 Django 肯定避不开 MVC 模式,即模型(Model)-视图(View)-控制器(Controller),通过将业务逻辑、数据、界面显示分离的方法组...

    唐郑望

扫码关注云+社区

领取腾讯云代金券