函数装饰器

  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, ...) # 检查用户设备类型,版本号等等
    ...

python 进阶篇 函数装饰器和类装饰器的更多相关文章

  1. python进阶篇

    python进阶篇 import 导入模块 sys.path:获取指定模块搜索路径的字符串集合,可以将写好的模块放在得到的某个路径下,就可以在程序中import时正确找到. ​ import sys ...

  2. Python进阶(十四)----空间角度研究类,类与类之间的关系

    Python进阶(十四)----空间角度研究类,类与类之间的关系 一丶从空间角度研究类 对象操作对象属性 class A(): address = '沙河' def __init__(self, na ...

  3. Python进阶(二)----函数参数,作用域

    Python进阶(二)----函数参数,作用域 一丶形参角度:*args,动态位置传参,**kwargs,动态关键字传参 *args: ​ 动态位置参数. 在函数定义时, * 将实参角度的位置参数聚合 ...

  4. typescript装饰器定义 类装饰器 属性装饰器 装饰器工厂

    /* 装饰器:装饰器是一种特殊类型的声明,它能够被附加到类声明,方法,属性或参数上,可以修改类的行为. 通俗的讲装饰器就是一个方法,可以注入到类.方法.属性参数上来扩展类.属性.方法.参数的功能. 常 ...

  5. Python进阶(三)----函数名,作用域,名称空间,f-string,可迭代对象,迭代器

    Python进阶(三)----函数名,作用域,名称空间,f-string,可迭代对象,迭代器 一丶关键字:global,nonlocal global 声明全局变量: ​ 1. 可以在局部作用域声明一 ...

  6. Python进阶(一)----函数

    Python进阶(一)----函数初识 一丶函数的初识 什么函数: ​ 函数是以功能为导向.一个函数封装一个功能 函数的优点: ​ 1.减少代码的重复性, ​ 2.增强了代码的可读性 二丶函数的结构 ...

  7. Python入门篇-函数、参数及参数解构

    Python入门篇-函数.参数及参数解构 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.函数概述 1>.函数的作用即分类 函数 数学定义:y=f(x) ,y是x的函数,x ...

  8. Java类载入器(一)——类载入器层次与模型

    类载入器   虚拟机设计团队把类载入阶段中的"通过一个类的全限定名来获取描写叙述此类的二进制字节流"这个动作放到Java虚拟机外部去实现.以便让应用程序自己决定怎样去获取所须要的类 ...

  9. python 装饰器(五):装饰器实例(二)类装饰器(类装饰器装饰函数)

    回到装饰器上的概念上来,装饰器要求接受一个callable对象,并返回一个callable对象(不太严谨,详见后文). 那么用类来实现也是也可以的.我们可以让类的构造函数__init__()接受一个函 ...

随机推荐

  1. 在TensorFlow中实现文本分类的卷积神经网络

    在TensorFlow中实现文本分类的卷积神经网络 Github提供了完整的代码: https://github.com/dennybritz/cnn-text-classification-tf 在 ...

  2. Tensorboard 详解(上篇)

    花间提壶华小厨 1. Tensorboard简介 对大部分人而言,深度神经网络就像一个黑盒子,其内部的组织.结构.以及其训练过程很难理清楚,这给深度神经网络原理的理解和工程化带来了很大的挑战.为了解决 ...

  3. ICCV 2019|70 篇论文抢先读,含目标检测/自动驾驶/GCN/等(提供PDF下载)

    虽然ICCV2019已经公布了接收ID名单,但是具体的论文都还没放出来,为了让大家更快得看论文,我们汇总了目前已经公布的大部分ICCV2019 论文,并组织了ICCV2019论文汇总开源项目(http ...

  4. 给 EF Core 查询增加 With NoLock

    给 EF Core 查询增加 With NoLock Intro EF Core 在 3.x 版本中增加了 Interceptor,使得我们可以在发生低级别数据库操作时作为 EF Core 正常运行的 ...

  5. coding++: java把一个整数拆分为单个值

    方式一: int num = 100; int[] ary = new int[(num+"").length()]; for(int i = ary.length-1;i> ...

  6. h5 js数组Array方法总结

    重新复习数组方法. 一.首先说一下构建一个数组. 1.直接定义一个数组. var a = [1,2,3]; 2.通过Array 对象new一个数组,但Array对象根据传参的不同会返回不同的数组对象. ...

  7. STM32F103ZET6系统定时器SysTick

    1.系统定时器SysTick的简介 系统定时器SysTick属于内核外设,内嵌在NVIC中.SysTick是一个24位的向下递减的计数器,计数器根据SysTick的时钟源计数,当SysTick的计数器 ...

  8. iapp,iapp http请求,iapp解析json数据

    iapp发送http请求,并解析json数据 //http操作 t() { s a = "http://wap.baidu.com/" //目标url hs(a, null, nu ...

  9. jsonpath 字典中取值

    jsonpath 第三方模块 def getsign(): url="http://api.nnzhp.cn/api/user/login" data = {"usern ...

  10. C++语言实现链式栈

    在之前写的C语言实现链式栈篇博文中,我已经给大家大概介绍了关于链式栈的意义以及相关操作,我会在下面给大家分享百度百科对链式栈的定义,以及给大家介绍利用C++实现链式栈的基本操作. 百度百科链式栈 链式 ...