美文网首页前端开发那些事儿
python设计模式5装饰器

python设计模式5装饰器

作者: python测试开发 | 来源:发表于2021-07-08 14:54 被阅读0次

    第二个值得学习的结构模式是装饰器模式,它允许程序员以透明的方式(影响其他对象)动态地给对象增加能力。

    可以用Pythonic的方式来写装饰器(意味着使用语言的特性),这要归功于内置的装饰器特性(https://docs.python.org/3/reference/compound_stmts.html#function)。

    Python 装饰器是一个可调用的(函数、方法或类),它获得一个函数对象 func_in 作为输入,并返回另一个函数对象 func_out。它用于扩展函数、方法或类的行为。

    真实世界的例子

    装饰器模式通常用于扩展对象的功能。在日常生活中,这种扩展的例子有:在枪上加一个消音器,使用不同的相机镜头等等。

    Django框架中有大量装饰器

    • 限制某些HTTP请求对视图的访问
    • 控制
    • 按单个视图控制压缩
    • 基于特定HTTP请求头控制缓存

    Pyramid框架和Zope应用服务器也使用装饰器来实现各种目标。

    • 将函数注册为事件订阅者
    • 以特定权限保护一个方法
    • 实现适配器模式

    应用

    装饰器模式在跨领域方面大放异彩:

    • 数据验证
    • 缓存
    • 日志
    • 监控
    • 调试
    • 业务规则
    • 加密

    使用修饰器模式的另一个常见例子是(Graphical User Interface,GUI)工具集。在GUI工具集中,我们希望能够将一些特性,比如边框、阴影、颜色以及滚屏,添加到组件/控件。

    实例

    所有的递归函数都可以从缓存中受益,所以让我们尝试返回前n个数字之和的函数number_sum()。

    def number_sum(n): 
        '''Returns the sum of the first n numbers''' 
        assert(n >= 0), 'n must be >= 0' 
        
        if n == 0:
            return 0
        else:
            return n + number_sum(n-1)  
     
    if __name__ == '__main__': 
        from timeit import Timer 
        t = Timer('number_sum(30)', 'from __main__ import number_sum')
        print('Time: ', t.timeit())
    

    执行输出耗时:Time: 34.952999532999456

    下面的代码中,我们使用dict来缓存已经计算好的和。我们还改变了传递给number_sum()函数的参数。我们想计算前300个数字的和,而不是只计算前30个。

    sum_cache = {0:0}
      
    def number_sum(n): 
        '''Returns the sum of the first n numbers''' 
        assert(n >= 0), 'n must be >= 0'
        
        if n in sum_cache:
            return sum_cache[n]
        res = n + number_sum(n-1)
        # Add the value to the cache
        sum_cache[n] = res
        return res
             
    if __name__ == '__main__': 
        from timeit import Timer 
        t = Timer('number_sum(300)', 'from __main__ import number_sum')
        print('Time: ', t.timeit())
    

    执行输出耗时:Time: 1.2133596080002462。快了但是单码复杂了,且不方便复用。改用lru_cache装饰器会更清晰:

    from functools import lru_cache
    
    @lru_cache
    def number_sum(n): 
        '''Returns the sum of the first n numbers''' 
        assert(n >= 0), 'n must be >= 0' 
        
        if n == 0:
            return 0
        else:
            return n + number_sum(n-1)  
     
    if __name__ == '__main__': 
        from timeit import Timer 
        t = Timer('number_sum(30)', 'from __main__ import number_sum')
        print('Time: ', t.timeit())
    

    相关文章

      网友评论

        本文标题:python设计模式5装饰器

        本文链接:https://www.haomeiwen.com/subject/lkqtpltx.html