首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >python设计模式5装饰器

python设计模式5装饰器

原创
作者头像
前端小tips
修改2021-11-24 13:52:41
修改2021-11-24 13:52:41
22400
代码可运行
举报
文章被收录于专栏:前端文章小tips前端文章小tips
运行总次数: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()。

代码语言:javascript
代码运行次数:0
运行
复制
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个。

代码语言:javascript
代码运行次数:0
运行
复制
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装饰器会更清晰:

代码语言:javascript
代码运行次数:0
运行
复制
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())

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
作者已关闭评论
0 条评论
热度
最新
推荐阅读
目录
  • 真实世界的例子
  • 应用
  • 实例
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档