简单无门槛,3分钟学会 Python 装饰器

一、引出装饰器功能

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. 代码逻辑解释

  1. hello_world = decorator_func(hello_world)这段代码表示:由变量 hello_world 来接收 decorator_func 函数返回的内部函数对象 inner_wrapper

  2. hello_world()这段代码表示:调用内部函数 inner_wrapper(), 而内部函数 inner_wrapper()中又调用了原函数 hello_world(), 因此输出结果先是打印内部函数 inner_wrapper() 里的“do other something except func of args.”, 然后再输出打印原函数 hello_world() 里的“say hello world to everybody!”

  3. 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(里面还有工作内推机会,毕竟我们是关系社会。)

软件测试面试文档

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

面试文档获取方式:

猜你喜欢

转载自blog.csdn.net/wx17343624830/article/details/129928680
今日推荐