函数装饰器

  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. Java——类的定义

    对象和类的关系:有一个学生 ,需要在表格上填写自己的信息 ,那么这个打印机就像一个类 ,打印出的表格就是一个对象,用类创建对象,学生填的信息 ,就是我所初始化的信息. 类的组成:由 属性(也叫成员变量 ...

  2. ElasticSearch 9200 9300 端口

    9300端口: ES节点之间通讯使用 9200端口: ES节点 和 外部 通讯使用 9300是TCP协议端口号,ES集群之间通讯端口号 9200端口号,暴露ES RESTful接口端口号

  3. 28. 实现 strStr()

    d地址:https://leetcode-cn.com/problems/implement-strstr/ <?php /** 实现 strStr() 函数. 给定一个 haystack 字符 ...

  4. 使用onclick/表单submit跳转到其他页面

    使用onclick 如果是本页显示可以直接用location,方法如下: - onclick="javascript:window.location.href='URL'" - o ...

  5. fiddler详解

    一.介绍Fiddler是一个http协议调试工具,能记录并检查电脑和互联网之间的http通讯,设置断点,查看所有的“进出”fiddler的数据(cookie,html,js,css等文件) 通常可从以 ...

  6. 并发——深入分析CountDownLatch的实现原理

    一.前言   最近在研究java.util.concurrent包下的一些的常用类,之前写了AQS.ReentrantLock.ArrayBlockingQueue以及LinkedBlockingQu ...

  7. 家庭版记账本app开发之关于(数据库查找出数据)圆饼图的生成

    这次完成的主要的怎样从数据库中调出数据.之后通过相关的数据,生成想要的圆饼图.以方便用户更加直观的看见关于账本的基本情况. 在圆饼图生成中用到了一些外部资源 具体的import如下: import c ...

  8. python工业互联网监控项目实战2—OPC

    OPC(OLE for Process Control)定义:指为了给工业控制系统应用程序之间的通信建立一个接口标准,在工业控制设备与控制软件之间建立统一的数据存取规范.它给工业控制领域提供了一种标准 ...

  9. wireshark抓包实战(二),第一次抓包

    1.选择网卡. 因为wireshark是基于网卡进行抓包的,所以这时候我们必须选取一个网卡进行抓包.选择网卡一般有三种方式 (1)第一种 当我们刚打开软件是会自动提醒您选择,例如: (2)第二种 这时 ...

  10. 【第一章】黎姿的python学习笔记