函数装饰器

  1. 简单装饰器

    def my_decorator(func):
    def wrapper():
    print('wrapper of decorator')
    func()
    return wrapper def greet():
    print('hello world') greet = my_decorator(greet)
    greet() # 输出
    # wrapper of decorator
    # hello world

    上述代码在 Python 中有更简单、更优雅的表示:

    def my_decorator(func):
    def wrapper():
    print('wrapper of decorator')
    func()
    return wrapper @my_decorator
    def greet():
    print('hello world') greet() # 输出
    # wrapper of decorator
    # hello world
  2. 带参数的装饰器

    def my_decorator(func):
    def wrapper(*args, **kwargs):
    print('wrapper of decorator')
    func(*args, **kwargs)
    return wrapper @my_decorator
    def greet(message):
    print(message) greet('hello world') # 输出
    # wrapper of decorator
    # hello world
  3. 自定义参数的装饰器

    def repeat(num):
    def my_decorator(func):
    def wrapper(*args, **kwargs):
    for i in range(num):
    print('wrapper of decorator {}'.format(i))
    func(*args, **kwargs)
    return wrapper
    return my_decorator @repeat(4)
    def greet(message):
    print(message) greet('hello world') # 输出:
    # wrapper of decorator 0
    # hello world
    # wrapper of decorator 1
    # hello world
    # wrapper of decorator 2
    # hello world
    # wrapper of decorator 3
    # hello world
  4. 原函数还是原函数吗?

    试着打印出 greet() 函数的一些元信息:

    greet.__name__
    ## 输出
    'wrapper' help(greet)
    # 输出
    Help on function wrapper in module __main__: wrapper(*args, **kwargs)

    greet() 函数被装饰以后,它的元信息变了。元信息告诉我们“它不再是以前的那个 greet() 函数,而是被 wrapper() 函数取代了”。

    为了解决这个问题,通常使用内置的装饰器@functools.wrap,它会帮助保留原函数的元信息(也就是将原函数的元信息,拷贝到对应的装饰器函数里)。

    import functools
    
    def my_decorator(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
    print('wrapper of decorator')
    func(*args, **kwargs)
    return wrapper @my_decorator
    def greet(message):
    print(message) greet.__name__ # 输出
    'greet'

类装饰器

实际上,类也可以作为装饰器。类装饰器主要依赖于函数__call__(),每当你调用一个类的示例时,函数__call__()就会被执行一次。


class Count:
def __init__(self, func):
self.func = func
self.num_calls = 0 def __call__(self, *args, **kwargs):
self.num_calls += 1
print('num of calls is: {}'.format(self.num_calls))
return self.func(*args, **kwargs) @Count
def example():
print("hello world") example() # 输出
num of calls is: 1
hello world example() # 输出
num of calls is: 2
hello world

我们定义了类 Count,初始化时传入原函数 func(),而__call__()函数表示让变量 num_calls 自增 1,然后打印,并且调用原函数。因此,在我们第一次调用函数 example() 时,num_calls 的值是 1,而在第二次调用时,它的值变成了 2

装饰器的应用

  • 身份认证 authenticate

  • 日志记录

  • 输入合理性检查 validation_check

  • 缓存 lru_cache

    通常使用缓存装饰器,来包裹这些检查函数,避免其被反复调用,进而提高程序运行效率,比如写成下面这样

    @lru_cache
    def check(param1, param2, ...) # 检查用户设备类型,版本号等等
    ...

最新文章

  1. 【转】MySQL批量SQL插入各种性能优化
  2. 烂泥:centos6.4服务器添加新硬盘
  3. linux内存回收 内核参数
  4. rJava配置
  5. 通过AOP 实现异常统一管理
  6. BNUOJ-26580 Software Bugs KMP匹配,维护
  7. SpeeDO —— 并行深度学习系统
  8. Web Service 的服务端的引用
  9. WebApi Gzip(Deflate) 压缩请求数据
  10. CATransform3D参数的意义
  11. 第一百节,JavaScript表达式中的运算符
  12. js字符串 数组处理
  13. 全球性WannaCry蠕虫勒索病毒感染前后应对措施
  14. 【.NET Core】docker Jenkins ASP.NET Core自动化部署
  15. linux yum配置代理
  16. Druid(新版starter)在SpringBoot下的使用以及优点
  17. Linux sys_call_table变动检测
  18. lua 语言笔记
  19. SiteCore Experience Analytics-体验分析
  20. 【计算机视觉】KCF算法

热门文章

  1. Springboot + Freemarker(一)
  2. Chrome 经典插件
  3. SpringBoot使用RedisTemplate操作Redis时,key值出现 \xac\xed\x00\x05t\x00\tb
  4. 怎么在三层架构中使用Quartz.Net开源项目(与数据库交互)
  5. MATLAB GUI设计(3)
  6. 【Ubuntu】常用命令汇总,整理ing
  7. 手工注入——MySQL手工注入实战和分析
  8. 运行npm安装wepy2踩坑error EEXIST 问题
  9. Appium:We shut down because no new commands came in
  10. vue中的js引入图片,使用require相关问题