python 装饰器的使用总结

本文介绍Python装饰器的基本概念及其用途,通过实例展示了如何利用装饰器为函数添加额外的功能,如统计函数执行时间,并讨论了如何处理带参数的装饰器及保持原始函数的元信息。

python装饰器:扩展原来函数功能的一种函数(它返回的是一个函数)。

作用:在不修改原代码的基础上给原函数增加新的功能,一般而言我们原始的函数需要增加一些功能,最直接的方法就是去原代码函数中进行修改,那么如果许多个函数都需要增加某个功能呢?这样就特别浪费时间,so,python的装饰器就这么厉害,接下来我们通过例子来了解python的装饰器。

原始函数(举比较简单的例子):

def func_test1():
print("This is a function named function_test1")

def func_test2():
print("This is a function named function_test2")


突然有一天我们需要在在所有函数增加统计函数的执行时间功能,此时可以写一个装饰器(可以看到该装饰器接收的是一个函数名,返回的也是一个函数):

def decorator(func):
def wrapper():
startime = time.time()
func()
endtime = time.time()
print(func.__name__ + " spend time " + str(endtime-startime))
return wrapper

那么问题来了,增加这个装饰器函数就可以了吗?当然不是,我们需要使用“@”符号来引用它,在所有需要修改的函数之前添加“@装饰器函数名”。

@decorator
def func_test1():
print("This is a function named function_test1")

@decorator
def func_test2():
print("This is a function named function_test2")

func_test1()
func_test2()


执行结果:

PS D:\python\class\decorator> python .\r2.py
This is a function named function_test1
func_test1 spend time 0.00029206275939941406
This is a function named function_test2
func_test2 spend time 0.0
PS D:\python\class\decorator>


上面的装饰器或许对于初学的你还有些不是很清楚,接下来举个带参数的装饰器或许你会恍然大悟(通过参数对应的输出来理解装饰器):

def decorator(func):
def wrapper(*args):
startime = time.time()
func(*args)
endtime = time.time()
print(func.__name__ + " spend time " + str(endtime-startime))
return wrapper

@decorator
def func_test1(func_arg1):
print("This is a function named " + func_arg1)

@decorator
def func_test2(func_arg1,func_arg2):
print("This is a function named " + func_arg1)
print("This is a function named " + func_arg2)

func_test1('function1')
func_test2('function1','function2')


运行结果:

PS D:\python\class\decorator> python .\r2.py
This is a function named function1
func_test1 spend time 0.0
This is a function named function1
This is a function named function2
func_test2 spend time 0.0004956722259521484
PS D:\python\class\decorator>

注意:装饰器嵌套函数使用的是可变参数,为了方式原始函数带有不同个数的参数。

问题:如果存在关键字参数,装饰器如果写呢?同理我们只需要在装饰函数中添加关键字形参(在实际应用中比较少用)。

def decorator(func):
def wrapper(*args,**kw):
startime = time.time()
func(*args,**kw)
endtime = time.time()
print(func.__name__ + " spend time " + str(endtime-startime))
return wrapper

@decorator
def func_test1(func_arg1):
print("This is a function named " + func_arg1)

@decorator
def func_test2(func_arg1,func_arg2):
print("This is a function named " + func_arg1)
print("This is a function named " + func_arg2)

@decorator
def func_test3(func_arg1,func_arg2,**kw):
print("This is a function named " + func_arg1)
print("This is a function named " + func_arg2)
print("keyword params " + str(kw))

func_test1('function1')
func_test2('function1','function2')
func_test3('function1','function2',a=1,b=False,c='123')

运行结果:

PS D:\python\class\decorator> python .\r2.py
This is a function named function1
func_test1 spend time 0.0004956722259521484
This is a function named function1
This is a function named function2
func_test2 spend time 0.0004944801330566406
This is a function named function1
This is a function named function2
keyword params {'a': 1, 'b': False, 'c': '123'}
func_test3 spend time 0.0004980564117431641
PS D:\python\class\decorator>


我们会发现:加上装饰器func_test1.__name__的值是wrapper,帮助信息也变成了wrapper的信息,是因为我们的函数名称传递给装饰器后实质上执行的是wrapper函数,这样就会造成影响了我们的原始代码的结果。

def decorator(func):
def wrapper():
startime = time.time()
func()
endtime = time.time()
print(func.__name__ + " spend time " + str(endtime-startime))
return wrapper

@decorator
def func_test1():
'''
This function is a test
'''
print("This is a function named " + func_test1.__name__)

func_test1()
help(func_test1)


PS D:\python\class\decorator> python .\r3.py
This is a function named wrapper
func_test1 spend time 0.0005042552947998047
Help on function wrapper in module __main__:

wrapper()

PS D:\python\class\decorator>

对于这个影响我们可以通过引入装饰wraps来避免这个问题,我们需要从functiontools这个模块库加载wraps:

import time
from functools import wraps

def decorator(func):
@wraps(func)
def wrapper():
startime = time.time()
func()
endtime = time.time()
print(func.__name__ + " spend time " + str(endtime-startime))
return wrapper

@decorator
def func_test1():
'''
This function is a test
'''
print("This is a function named " + func_test1.__name__)

func_test1()
help(func_test1)

PS D:\python\class\decorator> python .\r3.py
This is a function named func_test1
func_test1 spend time 0.0
Help on function func_test1 in module __main__:

func_test1()
This function is a test

PS D:\python\class\decorator>

可以看出原始函数的帮助信息和名称不变,是因为wraps装饰器参数func接收的是原始函数,它会把原有函数的一系列信息复制到wrapper函数中。





评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值