加入收藏 | 设为首页 | 会员中心 | 我要投稿 银川站长网 (https://www.0951zz.com/)- 云通信、基础存储、云上网络、机器学习、视觉智能!
当前位置: 首页 > 综合聚焦 > 编程要点 > 语言 > 正文

python装饰器函数怎么运用 有哪些知识点

发布时间:2023-09-13 12:51:45 所属栏目:语言 来源:
导读:这篇文章我们来了解“python装饰器函数怎么使用,有哪些知识点”的内容,小编通过实际的案例向大家展示了操作过程,简单易懂,有需要的朋友可以参考了解看看,那么接下来就跟随小编的思路来往下学习吧,希

这篇文章我们来了解“python装饰器函数怎么使用,有哪些知识点”的内容,小编通过实际的案例向大家展示了操作过程,简单易懂,有需要的朋友可以参考了解看看,那么接下来就跟随小编的思路来往下学习吧,希望对大家学习或工作能有帮助。

假如我写了一个函数 f

def f():

print('hello')

之后我想知道这段函数执行所要的时间,这好办,我只要将代码改为如下就行

import time

def f():

start = time.time() #获取程序执行开始的时间

print('hello')

end = time.time() #获取程序执行结束的时间

print(end - start) #得出函数f执行所要时间

f()

但之后我有写了无数个函数f2,f3……fn,我想知道每个函数执行所需要的时间,那么如果都像上面一样改,岂不是很闹心?还是不行,因为这样实在是太麻烦了。那怎么办呢?于是灵机一动,写了一个timer函数。。。

import time

def timer(func):

start = time.time()

func()

print(time.time() - start)

def f():

print('hello')

def f2():

print('xorld')

timer(f)

timer(f2)

这样看起来是不是简单多啦?不管我们写了多少个函数都可以调用这个计时函数来计算函数的执行时间

但是如果我只想用原来的方式f1(),f2(),fn()调用了这个函数,函数在原本执行输出的结果不变的前提下还可以增加计算时间的功能,而不是调用timer(f),timer(f2)才能计算时间,这该怎么办呢?

看了下面的装饰器函数你就会知道如何解决这个问题

一、装饰器 —— 形成过程

以下就是解决上面问题的代码的简单版:

import time

def f():

print('hello')

 

def timer(func):

def inner():

start = time.time()

func()

print(time.time() - start)

return inner

f = timer(f)

f()

还是这句话我只想用原来的方式f1(),f2(),fn()调用了这个函数,函数在原本执行输出的结果不变的前提下还可以增加计算时间的功能,但我还是要在函数 f 执行前写 f = timer(f)在这一串代码,是不是觉得碍眼?python的开发者也觉得碍眼,所以python的开发者就为我们提供了一句语法糖来解决这个问题!

二、装饰器 —— 初识语法糖

用@timmer代替f = timer(f),这就是一句语法糖。

import time

def timer(func):

def inner():

start = time.time()

func()

print(time.time() - start)

return inner

@timer #==> 写着这句话就相当于执行了f = timer(f)

def f():

print('hello')

f()

三、装饰器 ——本质与功能

1、本质

装饰器的本质就是一个闭包函数

2、功能

在不修改原函数及其调用方式的情况下对原函数功能进行扩展

四、装饰器 —— 装饰带参数,返回值的装饰器

1、装饰带一个参数的函数

刚才我们写的装饰器都是装饰不带参数的函数,现在要装饰一个带参数的函数怎么办呢?

import time

def timer(func):

def inner(a):

start = time.time()

func(a)

print(time.time() - start)

return inner

@timer

def f(a):

print(a)

f('hello')

2、装饰多个带有不同参数但无返回值的函数

其实装饰带参的函数并不是什么难事,但假如你有两个函数,需要传递的参数不一样呢,比如 函数func1有两个参数func1(a ,b),函数func 2只有一个参数func2(a), 且它们都想用这个装饰器装饰,做到计算函数执行时间?这怎么办呢?那就用下面代码。

import time

def timer(func):

def inner(*args,**kwargs):

start = time.time()

re = func(*args,**kwargs)

print(time.time() - start)

return re

return inner

@timer #==> func1 = timer(func1)

def func1(a,b):

print('in func1')

@timer #==> func2 = timer(func2)

def func2(a):

print('in func2 and get a:%s'%(a))

return 'fun2 over'

func1('aaaaaa','bbbbbb')

print(func2('aaaaaa'))

输出结果:

in func1

0.0

in func2 and get a:aaaaaa

0.0

fun2 over

3、装饰多个带有不同参数且有返回值的函数

现在参数的问题已经完美的解决了,可是如果你的函数是有返回值的呢?用上面的代码你就拿不到返回值了那究竟要如何解决这个问题呢?那就看下面的代码吧!

import time

def timer(func):

def inner(*args,**kwargs):

start = time.time()

re = func(*args,**kwargs)

print(time.time() - start)

return re

return inner

@timer #==> func2 = timer(func2)

def func2(a):

print('in func2 and get a:%s'%(a))

return 'fun2 over'

func2('aaaaaa')

print(func2('aaaaaa'))

输出结果:

in func2 and get a:aaaaaa

0.0

in func2 and get a:aaaaaa

0.0

fun2 over

4、多个装饰器装饰同一个函数

有些时候,我们也会用到多个装饰器装饰同一个函数的情况。

ef wrapper1(func): #func ----- f

def inner1():

print('wrapper1 ,before func')

func()

print('wrapper1 ,after func')

return inner1

def wrapper2(func):

def inner2():

print('wrapper2 ,before func')

func()

print('wrapper2 ,after func')

return inner2

@wrapper2 #f = wrapper2(f) ----->> wrapper2(inner1) == inner2

@wrapper1 #f = wrapper1(f) = inner

def f():

print('in f')

f() #===>>inner2

#多个装饰器装饰同一个函数

输出结果:

wrapper2 ,before func

wrapper1 ,before func

in f

wrapper1 ,after func

wrapper2 ,after func

五、装饰器 —— 装饰器进阶与优化

1、带参数的装饰器

上面那个装饰器已经非常beautiful了,但是还有一个问题,如果我给代码中无数个函数都加了@timer这个语法糖,如果之后我又不想用它了那岂不是又要每个去将它注释,没日没夜忙活3天?岂不是特别麻烦,为了使装饰器不用时能够更好的回收而不是一个一个去注释或者删除 我们引入带参数的装饰器概念

'''

为了使装饰器不用时能够更好的回收而不是一个一个去注释或者删除

我们引入带参数的装饰器概念

'''

import time

'''FLAGE的目的是用它控制装饰器的开关,

那么当我们不用的时候就不要一个一个去注释只需将True改为False就行'''

FLAGE = True

def timmer_out(flag):

def timmer(func):

def inner(*args,**kwargs):

if flag:

start = time.time()

ret = func(*args,**kwargs)

end = time.time()

print(end - start)

return ret

else:

ret = func(*args, **kwargs)

return ret

return inner

return timmer

@timmer_out(FLAGE)

#timmer_out(FLAGE)

# 也相当于执行 timmer_out(FLAGE)--->>返回timmer———————>>@timmer(wahaha = timmer(wahaha))

def wahaha():

time.sleep(0.1) #不休息的话函数执行的太快难以计算时间

print('wahahahahahaha')

wahaha()

@timmer_out(FLAGE)

def erguotou():

time.sleep(0.1) #不休息的话函数执行的太快难以计算时间

print('erguotoutoutou')

erguotou()

输出结果:

wahahahahahaha

0.10152268409729004

erguotoutoutou

0.10795140266418457

2、防止函数必要信息失效

'''

print(wahaha.__name__) #查看字符串格式的函数名

print(wahaha.__doc__) #查看一个函数的注释

'''

#下面用__name__查看holiday的函数名

from functools import wraps

def wrapper(func):

@wraps(func) #加在最内层函数正上方

def inner(*args,**kwargs):

print('在被装饰的函数执行之前做的事')

ret = func(*args,**kwargs)

print('在被装饰的函数执行之后做的事')

return ret

return inner

@wrapper #holiday = wrapper(holiday)

def holiday(day):

'''

这是一个放假通知

:param day:

:return:

'''

print('全体放假%s天'%day)

return '好开心'

print(holiday.__name__)

print(holiday.__doc__)

'''

结果是inner和None 但我们想要的是打印holiday的字符串格式的函数名和函数的注释这时该怎么办?

解决方法就是 from functools import wraps

使用语法是@wraps(被装饰的函数名)

'''

输出结果:

holiday

这是一个放假通知

:param day:

:return:

六、装饰器 —— 装饰原则

1、开放封闭原则

1.对原函数的功能扩展是开放的

为什么要对功能扩展开放呢?

对于任何一个程序来说,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改。所以我们必须允许后来扩展、添加新功能。

2.对修改是封闭的

为什么要对修改封闭呢?

就像我们刚刚提到的,因为我们写的一个函数,很有可能在其他地方已经被导入使用了,如果这个时候我们对其进行了修改,很有可能影响其他已经正在使用该函数的代码。

装饰器就完美遵循了这个开放封闭原则。这就是学装饰器的初衷

小结:

1、装饰器的固定格式(模板)

#格式一

def timer(func):

def inner(*args,**kwargs):

'''执行函数之前要做的'''

re = func(*args,**kwargs)

'''执行函数之后要做的'''

return re

return inner

#格式二

from functools import wraps

def deco(func):

@wraps(func) #加在最内层函数正上方

def wrapper(*args,**kwargs):

return func(*args,**kwargs)

return wrapper

到此,关于“python装饰器函数怎么使用,有哪些知识点”的学习就结束了,希望能够解决大家的疑惑,另外大家动手实践也很重要,对大家加深理解和学习很有帮助。

(编辑:银川站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章