当前位置: 首页 > news >正文

python装饰器教程_Python装饰器(你想知道的这里都有)!最详细的教程!

1. 装饰器的定义

就是给已有函数增加额外功能的函数,它本质上就是一个闭包函数。

装饰器的功能特点:

不修改已有函数的源代码

不修改已有函数的调用方式

给已有函数增加额外的功能

闭包和装饰器的区分:

如果闭包函数的参数有且只有一个,并且是函数类型,那么这个闭包函数称之为装饰器。

写代码要遵循开放封闭原则,它规定已经实现的功能代码不允许被修改,但可以被扩展。

2. 装饰器的示例代码

# 定义装饰器

def decorator(func):

def inner():

# 在内部函数里面对已有函数进行装饰

print('已添加登录认证')

func()

return inner

def comment():

print('发表评论')

# 调用装饰器对已有函数进行装饰,左边的comment=inner

comment = decorator(comment)

# 调用方式不变

comment()

3. 装饰器的语法糖写法

如果有多个函数都需要添加登录验证的功能,每次都需要编写func = decorator(func)这样代码对已有函数进行装饰,这种做法还是比较麻烦。

Python给提供了一个装饰函数更加简单的写法,那就是语法糖,语法糖的书写格式是: @装饰器名字,通过语法糖的方式也可以完成对已有函数的装饰

# 定义装饰器

def decorator(func):

def inner():

# 在内部函数里面对已有函数进行装饰

print('已添加登录认证')

func()

return inner

@decorator  # comment = decorator(comment) 装饰器语法糖对该代码进行了封装 左边comment=inner

def comment():

print('发表评论')

# 调用方式不变

comment()

4. 装饰器的执行时机

当 当前模块加载完成以后,装饰器会立即执行,对已有函数进行装饰。

# 定义装饰器

def decorator(func):

print('装饰器执行了')

def inner():

# 在内部函数里面对已有函数进行装饰

print('已添加登录认证')

func()

return inner

@decorator  # comment = decorator(comment) 装饰器语法糖对该代码进行了封装 左边comment=inner

def comment():

print('发表评论')

运行结果:

装饰器执行了

1

5. 装饰器的使用

5.1 装饰器的使用场景

函数执行时间的统计

输出日志信息

5.2 装饰器实现已有函数执行时间的统计

import time

def decorator(func):

def inner():

# 获取时间距离1970-1-1 0:0:1的时间差

begin = time.time()

func()

end = time.time()

result = end - begin

print(f'函数执行完成耗时:{result}')

return inner

@decorator

def work():

for i in range(10000):

print(i)

work()

6. 通用装饰器的使用

通用装饰器:可以装饰任意类型的函数

使用装饰器装饰已有函数的时候,内部函数的类型和要装饰的已有函数的类型保持一致

6.1 装饰带有参数的函数

def decorator(func):

def inner(num1, num2):

print('正在努力执行加法计算')

func(num1, num2)

return inner

@decorator

def add_num(num1, num2):

result = num1 + num2

print(f'结果为:{result}')

add_num(1, 2)

6.2 装饰带有参数、返回值的函数

def decorator(func):

def inner(num1, num2):

print('正在努力执行加法计算')

num = func(num1, num2)

return num

return inner

@decorator

def add_num(num1, num2):

result = num1 + num2

return result

result = add_num(1, 2)

print(f'结果为:{result}')

6.3 装饰带有不定长参数、返回值的函数

def decorator(func):

def inner(*args, **kwargs):

print('正在努力执行加法计算')

# *args:把元组里面的每一个元素,按照位置参数的方式进行传参

# **kwargs:把字典里面的每一个键值对,按照关键字的方式进行传参

num = func(*args, **kwargs)

return num

return inner

@decorator

def add_num(*args, **kwargs):

result = 0

for value in args:

result += value

for value in kwargs.values():

result += value

return result

result = add_num(1, 2, a=3)

print(f'结果为:{result}')

7. 多个装饰器的使用

多个装饰器的装饰过程:由内到外的一个装饰过程,先执行内部的装饰器,在执行外部的装饰器。

def make_div(func):

print('make_div装饰器执行了')

def inner():

result = '

' + func() + '
'

return result

return inner

def make_p(func):

print('make_p装饰器执行了')

def inner():

result = '

' + func() + '

'

return result

return inner

# 原理剖析:content = make_div(make_p(content))

# 分布拆解:content = make_p(content),内部装饰器完成,content = make_p.inner

#          content = make_div(make_p.inner)

@make_div

@make_p

def content():

return '人生苦短,我用python'

c = content()

print(c)

8. 带有参数的装饰器

带有参数的装饰器就是使用装饰器装饰函数的时候可以传入指定参数,语法格式: @装饰器(参数,…)

使用带有参数的装饰器,其实是在装饰器外面又包裹了一个函数,使用该函数接收参数,返回是装饰器,因为 @ 符号需要配合装饰器实例使用。

def return_decorator(flag):

# 装饰器只能接收一个参数并且是函数类型

def decorator(func):

def inner(a, b):

if flag == '+':

print('正在努力执行加法计算')

elif flag == '-':

print('正在努力执行减法计算')

func(a, b)

return inner

# 当调用函数的时候可以返回一个装饰器decorator

return decorator

@return_decorator('+')  # decorator = return_decorator('+'), @decorator => add_num = decorator(add_num)

def add_num(a, b):

result = a + b

print(result)

@return_decorator('-')

def sub_num(a, b):

result = a - b

print(result)

add_num(1, 2)

sub_num(1, 2)

正在努力执行加法计算 3 正在努力执行减法计算 -1

9. 类装饰器的使用

类装饰器:使用类装饰已有函数

class MyDecorator(object):

def __init__(self, func):

self.__func = func

# 实现__call__方法,表示对象是一个可调用对象,可以像调用函数一样进行调用

def __call__(self, *args, **kwargs):

# 对已有函数进行封装

print('马上就有下班啦')

self.__func()

@MyDecorator  # @MyDecorator => show = MyDecorator(show)

def show():

print('快要下雪啦')

# 执行show,就相当于执行MyDecorator类创建的实例对象,show() => 对象()

show()

扩展:

函数之所以能够调用,是因为函数内部实现了 __call__ 方法

10. 应用场景

收集函数的操作或错误日志记录

验证函数的使用权限

计算函数的运行时间

在ORM/DB模型操作时,通过属性方法动态地获取关联的数据

函数数据的缓存

定制函数的输入和输出(序列化和反序列化)

此文转载文,著作权归作者所有,如有侵权联系小编删除!

相关文章:

  • c盘python27文件夹可以删除嘛_C盘文件可以随便删除吗-百度经验
  • 时间同步失败_关于同步处理、异步处理的思考
  • openapi回调地址请求不通过_在实际开发中需要访问两个不同地址的跨域问题!...
  • pkg文件转图片_Go Gin 系列十二:优化配置结构及实现图片上传
  • python编程框架_整理了 34 个被吹爆了的Python开源框架
  • 编程实现路由算法_PLC数据采集怎么实现?
  • python http代理_python HTTP代理中转服务
  • wxpython使用简介_wxPython:事件处理介绍一
  • 必须声明标量变量 @sum_level。_Java变量
  • ubuntu localhost可以访问 ip不能访问_通过两次ssh tunnel访问gateway后主机上的jupyter notebook服务...
  • python形参和实参的含义_Python3函数的形参如何接收实参?
  • 在python将字符串中的空格转换为下划线_如何将下划线替换为空格,反之亦然?...
  • python图像锐化_opencv实现图片模糊和锐化操作
  • python中configparser函数_python基础14 ---函数模块4(configparser模块)
  • python接口自动化测试报告_python接口自动化(二十七)--html 测试报告——上(详解)...
  • Docker下部署自己的LNMP工作环境
  • DOM的那些事
  • JavaScript中的对象个人分享
  • JS字符串转数字方法总结
  • seaborn 安装成功 + ImportError: DLL load failed: 找不到指定的模块 问题解决
  • SOFAMosn配置模型
  • swift基础之_对象 实例方法 对象方法。
  • UEditor初始化失败(实例已存在,但视图未渲染出来,单页化)
  • v-if和v-for连用出现的问题
  • vue-router 实现分析
  • Vultr 教程目录
  • 从0搭建SpringBoot的HelloWorld -- Java版本
  • 从零开始的webpack生活-0x009:FilesLoader装载文件
  • 记一次和乔布斯合作最难忘的经历
  • 检测对象或数组
  • 简单基于spring的redis配置(单机和集群模式)
  • 免费小说阅读小程序
  • 普通函数和构造函数的区别
  • 七牛云假注销小指南
  • 实习面试笔记
  • 微服务框架lagom
  • RDS-Mysql 物理备份恢复到本地数据库上
  • Salesforce和SAP Netweaver里数据库表的元数据设计
  • 阿里云IoT边缘计算助力企业零改造实现远程运维 ...
  • 我们雇佣了一只大猴子...
  • # Swust 12th acm 邀请赛# [ K ] 三角形判定 [题解]
  • #1014 : Trie树
  • (14)学习笔记:动手深度学习(Pytorch神经网络基础)
  • (C语言)fread与fwrite详解
  • (el-Transfer)操作(不使用 ts):Element-plus 中 Select 组件动态设置 options 值需求的解决过程
  • (附源码)springboot工单管理系统 毕业设计 964158
  • (附源码)springboot社区居家养老互助服务管理平台 毕业设计 062027
  • (附源码)ssm高校升本考试管理系统 毕业设计 201631
  • (力扣)循环队列的实现与详解(C语言)
  • (六)c52学习之旅-独立按键
  • (每日持续更新)jdk api之FileReader基础、应用、实战
  • (十六)Flask之蓝图
  • (四)JPA - JQPL 实现增删改查
  • (算法)求1到1亿间的质数或素数
  • (一) springboot详细介绍