函数(四)---装饰器

1. 什么是装饰器?

装饰器是可调用的对象,其参数是另一个函数(被装饰的函数)。装饰器可能会处理被装饰的函数,然后把它返回,或者将其替换成另一个函数或可调用对象。

如果有一个名为decorate的装饰器(如下代码),

def decorate(func):
    def wrapper():
        print('wrapper 函数开始执行')
        start_time = time.perf_counter()
        func()
        end_time = time.perf_counter()
        print(f'函数的运行时间为:{end_time - start_time}')
        print('wrapper 函数结束')
    return wrapper

则:

def for_loop():
    print('for_loop函数开始执行')
    for i in range(1000):
        pass
    print('for_loop 函数结束')

new_for = decorate(for_loop)    #wrapper()
new_for()

等价于:

@decorate
def for_loop():
    print('for_loop函数开始执行')
    for i in range(1000):
        pass
    print('for_loop 函数结束')

for_loop()

上述两种写法结果一样,函数执行完之后得到的for_loop不一定是原来那个for_loop()函数,而是decorate(for_loop)返回的函数。

为了确认被装饰的函数会被替换,请看上边以下示例的控制台会话。

import time

def decorate(func):
    def wrapper():
        print('wrapper 函数开始执行')
        start_time = time.perf_counter()
        func()
        end_time = time.perf_counter()
        print(f'函数的运行时间为:{end_time - start_time}')
        print('wrapper 函数结束')
    return wrapper    #decorate返回wrapper函数对象


@decorate           #使用decorate装饰for_loop
def for_loop():
    print('for_loop函数开始执行')
    for i in range(100000):
        pass
    print('for_loop 函数结束')

for_loop()      #调用for_loop,其实会运行wrapper
"""
运行结果:
wrapper 函数开始执行
for_loop函数开始执行
for_loop 函数结束
函数的运行时间为:0.002172199999999999
wrapper 函数结束
"""
print(for_loop)     #发现for_loop 是wrapper的引用
# 运行结果:<function decorate.<locals>.wrapper at 0x01989580>

严格来说,装饰器只是语法糖。如前所示,装饰器可以像常规的可调用对象那样调用,其参数是另一个函数。

综上,装饰器的两大特性

1. 能把被装饰的函数替换成其他函数。

2. 装饰器在加载模块时立即执行。

2. 带有参数的装饰器

如果被修饰的函数带有参数,则装饰器中应该也放入一个参数, 且这个参数应该作为里层函数的参数进行传递。因为装饰器函数最终返回的是装饰器中的函数对象, 等价于被装饰的函数。

import time

def decorate(func):
    def wrapper(number):
        print('wrapper 函数开始执行')
        start_time = time.perf_counter()
        func(number)
        end_time = time.perf_counter()
        print(f'函数的运行时间为:{end_time - start_time}')
        print('wrapper 函数结束')
    return wrapper    #decorate返回wrapper函数对象


@decorate           #使用decorate装饰for_loop
def for_loop(number):
    print('for_loop函数开始执行')
    for i in range(number):
        pass
    print('for_loop 函数结束')

for_loop(100000)      #调用for_loop,其实会运行wrapper
"""
运行结果:
wrapper 函数开始执行
for_loop函数开始执行
for_loop 函数结束
函数的运行时间为:0.002172199999999999
wrapper 函数结束
"""

2. 带有可变参数的装饰器

import time

def decorate(func):
    def wrapper(*args):
        start_time = time.perf_counter()
        func(*args)
        end_time = time.perf_counter()
        print(f'函数的运行时间为:{end_time - start_time}')
    return wrapper    #decorate返回wrapper函数对象

@decorate
def welcome(*args):
    name, age = args
    if age >= 18:
        print(f'hello {name}, 你已成年')
    else:
        print(f' hello {name}, 你未成年')

welcome('Elsa', 19)

"""
运行结果:
hello Elsa, 你已成年
函数的运行时间为:2.1300000000001873e-05
"""
import time

def decorate(func):
    def wrapper(*args, **kwargs):
        start_time = time.perf_counter()
        func(*args, **kwargs)
        end_time = time.perf_counter()
        print(f'函数的运行时间为:{end_time - start_time}')
    return wrapper    #decorate返回wrapper函数对象

@decorate
def info(*args, **kwargs):
    name, gender = args
    print(f"姓名:{name}\n性别:{gender}\n爱好:{kwargs['hobby']}")

info('Elsa', 19, hobby = '乒乓球')

"""
运行结果:
姓名:Elsa
性别:19
爱好:乒乓球
函数的运行时间为:2.3700000000001498e-05
"""

3. 装饰器嵌套

 

 

def decorate1(func):
    def inner1():
        print('running decorate1')
        func()
    return inner1

def decorate2(func):
    def inner2():
        print('running decorate2')
        func()
    return inner2

@decorate1
@decorate2
def say_hi():
    print('hello')

"""
执行结果:
running decorate1
running decorate2
hello
"""

 

posted @ 2022-01-16 18:22  ElsaWang  阅读(71)  评论(0)    收藏  举报