一、引出装饰器功能
1. 输入
def decorator_func(func):
def inner_wrapper():
print('do other something except func of args.')
func()
return inner_wrapper
def hello_world():
print('say hello world to everybody!')
hello_world = decorator_func(hello_world)
hello_world()
2. 输出
do other something except func of args.
say hello world to everybody!
3. 代码逻辑解释
-
hello_world = decorator_func(hello_world)
这段代码表示:由变量 hello_world 来接收 decorator_func 函数返回的内部函数对象 inner_wrapper -
hello_world()
这段代码表示:调用内部函数 inner_wrapper(), 而内部函数 inner_wrapper()中又调用了原函数 hello_world(), 因此输出结果先是打印内部函数 inner_wrapper() 里的“do other something except func of args.”, 然后再输出打印原函数 hello_world() 里的“say hello world to everybody!” -
decorator_func()
函数此时相当于一个装饰器,它的功能是把真正需要执行的函数 hello_world() 包裹在函数内部,与此同时,还添加了一些非函数 hello_world() 的逻辑,这样也能保证原函数 hello_world() 逻辑不变
二、无参数 Python 装饰器
在 Python 中上面的代码还有更简单、优雅的编写方式如下
def decorator_func(func):
def inner_wrapper():
print('do other something except func of args.')
func()
return inner_wrapper
@decorator_func
def hello_world():
print('say hello world to everybody!')
hello_world()
@decorator_func
这里的@
被称之为语法糖
@decorator_func
替换了上面的hello_world = decorator_func(hello_world)
语句及其功能,形式看起来更加简洁
PS: 装饰器的作用:极大提高了函数的重复利用和程序的可读性
三、任意参数 Python 装饰器
使用场景
当有多个函数需要用到同一装饰器,且不同函数所需传递的参数数量或类型不一致时,可以在装饰器定义时使用任意数量和类型的参数
改造装饰器
def decorator_func(func):
def inner_wrapper(*args, **kwargs):
print('do other something except func of args.')
func(*args, **kwargs)
return inner_wrapper
@decorator_func
def hello_world(message):
print('say hello world to' + str(message))
@decorator_func
def hello_myself(name, word):
print(str(name) + 'say hello world to' + str(word))
hello_world('this is a message!')
hello_myself('nancy', 'hello world!')
四、内置装饰器@functools.wrap
1. 输入
def decorator_func(func):
def inner_wrapper(*args, **kwargs):
print('do other something except func of args.')
func(*args, **kwargs)
return inner_wrapper
@decorator_func
def hello_world(message):
print('say hello world to' + str(message))
print(hello_world.__name__)
print(help(hello_world))
2. 输出
inner_wrapper
Help on function inner_wrapper in module __main__:
inner_wrapper(*args, **kwargs)
从输出结果发现,hello_world() 函数被装饰器装饰以后,它的元信息变了
元信息输出结果说明“它不再是以前的那个 hello_world() 函数,而是被 inner_wrapper() 函数取代了”
可以使用内置的装饰器 @functools.wrap,解决元信息丢失的问题,@functools.wrap 会帮助保留原函数的元信息(工作原理是将原函数的元信息,拷贝到对应的装饰器函数里)
修改后代码实例
# 输入
import functools
def decorator_func(func):
@functools.wraps(func)
def inner_wrapper(*args, **kwargs):
print('do other something except func of args.')
func(*args, **kwargs)
return inner_wrapper
@decorator_func
def hello_world(message):
print(message)
print(hello_world.__name__)
# 输出
'hello_world'
五、类装饰器
上面讲到了函数作为装饰器的用法,实际上在 Python 中 类
也可以作为装饰器
,称为类装饰器
类装饰器主要依赖于函数__call_()
,每当你调用一个类的实例时,函数__call__()就会被执行一次
类装饰器实例代码
1. 输入
class SumNumber:
def __init__(self, func):
self.func = func
self.number_calls = 0
def __call__(self, *args, **kwargs):
self.number_calls += 1
print('number of calls is: {}'.format(self.number_calls))
return self.func(*args, **kwargs)
@SumNumber
def test_count():
print("hello world")
test_count()
test_count()
2. 输出
number of calls is: 1
hello world
number of calls is: 2
hello world
输入代码中定义了类 SumNumber,初始化时传入原函数 func(),而__call__() 函数定义逻辑让变量 number_calls 每次调用时自增 1,然后输出,同时调用原函数
所以在第一次调用函数 test_count() 时,number_calls 的值是 1,而在第二次调用时,它的值是在上一次调用的值的基础上再+1,所以值变成了 2
六、装饰器的嵌套
上面讲的示例都是一个装饰器的情况,但实际上在 Python 中也支持多个装饰器,也称做装饰器的嵌套,具体写法如下:
@decorator_func1
@decorator_func2
@decorator_func3
def hello_world():
print('hello world')
PS: 嵌套装饰器的执行顺序是由外到里
具体示例改造
1. 输入
import functools
def decorator_func1(func):
@functools.wraps(func)
def inner_wrapper(*args, **kwargs):
print('this is a message of execute decorator_func1')
func(*args, **kwargs)
return inner_wrapper
def decorator_func2(func):
@functools.wraps(func)
def inner_wrapper(*args, **kwargs):
print('this is a message of execute decorator_func2')
func(*args, **kwargs)
return inner_wrapper
@decorator_func1
@decorator_func2
def hello_world(message):
print(message)
hello_world('hello world!!!')
2. 输出
this is a message of execute decorator_func1
this is a message of execute decorator_func2
hello world!!!
最后: 下方这份完整的软件测试视频学习教程已经整理上传完成,朋友们如果需要可以自行免费领取【保证100%免费】
这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!
软件测试技术交流群社:786229024(里面还有工作内推机会,毕竟我们是关系社会。)
软件测试面试文档
我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。