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

Python 装饰器

1.装饰器基本概念

        装饰器就是给现有的函数添加功能,并且不改变它原有的调用方式,本质上就是一个高阶函数(参数是函数名并且返回函数名),在python中,万物皆对象,函数名也是一个对象可以被作为参数传递,这和C语言中的回调函数很相似。

2.装饰器

2.1 装饰器没有参数并且被装饰函数也没有参数

我们想要设计一个函数,能统计任何函数的运行时间,该怎么设计呢?

from time import time, sleepdef func1():sleep(3)print('in func1')def get_run_time(parameter_func):start_time = time()parameter_func()end_time = time()print('运行时间为:', end_time - start_time)get_run_time(func1)

这段代码中,get_run_time函数接收函数名作为参数,在函数体中记录时间并且调用对应的函数达到记录函数运行时间的功能

但是上面的函数已经不通过func1调用了,而是使用了另一个函数,所以它不是装饰器,那要怎么才能让他变为一个装饰器呢?很简单,让原函数被赋值为get_run_time函数不就得了?那需要get_run_time返回值也是一个函数,但是get_run_time中没有函数,所以我们需要在get_run_time中再定义一个函数(函数的嵌套定义),看下面的代码:

我们看到,在没有改变原函数的调用方式的前提下,达到了给func1新增计时的功能,这就是一个最简单的装饰器函数,但是它怎么不是 @classmethod 这种形式呢?别急,它可以转换为这种形式,因为 @ 是一个语法糖,它的本质和我们上面写的函数类似,看下面的代码:

from time import time, sleepdef func1():sleep(3)print('in func1')def get_run_time(parameter_func):def temp():start_time = time()parameter_func()end_time = time()print('运行时间为:', end_time - start_time)return temp@get_run_time   #实际上执行了 func2 = get_run_time(func2)
def func2(): sleep(5)print('in func2')
func1 = get_run_time(func1)
func1()
func2()

我们使用@这个语法糖给func2这个函数增加了功能,现在就和@classmethod一样了,并且也能完成相应的功能,下面是运行结果。

2.2 被装饰函数有参数

from time import time, sleepdef get_run_time(parameter_func):def temp():start_time = time()parameter_func()end_time = time()print('运行时间为:', end_time - start_time)return temp@get_run_time       
def func1(name):  sleep(3)print(f'我叫{name}','in func1')func1('小明')

这段代码会报错,TypeError: get_run_time.<locals>.temp() takes 0 positional arguments but 1 was given,因为:

执行 @get_run_time装饰器相当于执行 func1=get_run_time(func1)。

get_run_time返回内部的temp函数,所以func1 = temp,因此 func1('小明') == temp('小明'),但是temp是不接收参数的,因此改正方法就很清晰了,修改定义的temp函数,让它接收参数

2.3 装饰器本身带参数

from time import time, sleepdef get_run_time(parameter_func , time_type):print(time_type)def temp(*args, **kwargs):start_time = time()parameter_func(*args, **kwargs)end_time = time()print('运行时间为:', end_time - start_time)return temp@get_run_time(time_type = 'seconds')
def func1(name,age):sleep(3)print(f'我叫{name},今年{age}岁','in func1')func1('小明',20)

按照我们本来的想法,装饰器本身带参数,那么我在定义和调用时都给他一个参数不就完了吗?但是上面的代码会报错:TypeError: get_run_time() missing 1 required positional argument: 'parameter_func',因为parameter_func没有接收到值,所以我们需要修改装饰器 

为什么需要嵌套定义outer和inner呢?我们可以姑且这么理解:最外层get_run_time()消化了time_type,outer()消化了func1这个函数名,inner消化了name和age这两个实参。

2.4 被装饰函数带返回值

经过上面的分析,我们已经很清楚了,func1最后是得到最内层的函数地址,所以我们在最内层中保存通过函数名调用的func1的返回值,在inner运行结束后返回即可:

from time import time, sleepdef get_run_time( time_type):print(time_type)def outer(parameter_func):def inner(*args, **kwargs):start_time = time()ret = parameter_func(*args, **kwargs)end_time = time()print('运行时间为:', end_time - start_time)return retreturn inner  #outer返回inner的地址return outer  #get_run_time返回outer的地址@get_run_time(time_type = 'seconds')
def func1(name,age):sleep(3)print(f'我叫{name},今年{age}岁','in func1')return nameprint(func1('小明', 20))

2.5 总体对比


#被装饰函数带不带参数均可
def decorator1(func):def inner(*args, **kwargs):func(*args, **kwargs)return inner#装饰器本身带参数
def decorator2(para):"""对参数para的操作"""def outer(func):def inner(*args, **kwargs):func(*args, **kwargs)return innerreturn outer#被装饰函数带返回值
def decorator3(para):"""对参数para的操作"""def outer(func):def inner(*args, **kwargs):ret = func(*args, **kwargs)return retreturn innerreturn outer

相关文章:

  • 136只出现一次的数字
  • C++性能测评工具
  • 【数据库】在线体验KingbaseES平台,零门槛学习,并快速体验Oracle增改查全基础功能
  • MSPM0G3507学习笔记(二) 超便捷配置led与按键
  • linux thermal framework(5)_thermal core
  • 60days challenge day34
  • Vue3+TypeScript 导入枚举(Enum)最佳实践
  • Docker 镜像相关命令介绍与示例
  • 如何为你的工作站添加“一键切换显示器接口”功能?
  • 限流系列之三:TDMQ for Apache Pulsar 限流技术深度解析
  • 聊聊 Pulsar:Consumer 源码解析
  • Kafka 4.0.0集群部署
  • coze中怎么创建插件
  • KVM高级功能部署
  • 死锁、线程总结
  • 批量调用接口(ApiFox + Postman)
  • 【记录】Ubuntu挂载硬盘
  • ArcGIS Pro无插件加载(无偏移)天地图!一次添加长久使用
  • Langchain入门指南:一次讲清基本用法
  • jenkins打包问题jar问题
  • 佛山企业门户网站建设/seo推广编辑
  • 烟台百度网站建设推广/营销型企业网站推广的方法有哪些
  • 查找网站备案信息/seo关键词优化价格
  • 网站建设创新互联/引擎优化seo
  • vr 做的网站/成都网站建设技术支持
  • 仿站下载工具/搭建网站教程