欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

15 Python学习之装饰器

程序员文章站 2024-02-19 13:58:00
...


装饰器

装饰器:在不改变源函数的代码及调用方式的前提下,为其增加新的功能,装饰器就是一个函数,他的本质是闭包

装饰器开放封闭的原则:

开放:对代码的扩展开放

封闭:对源码的修改是封闭的

被装饰函数无参数,无返回值

例1:

import time

def timer(func):
    def inner():
        start_time = time.time()
        func()
        end_time = time.time()
        print(f'装饰器打印执行时间为:{round(end_time - start_time, 5)}')
    return inner            # 闭包,返回内层函数的引用

# show_info = timer(show_info)第一个show_info是一个新的变量,第二个show_info的函数名,@timer是show_info = timer(show_info)的简写,官方叫做语法糖
@timer
def show_info():
    print(f"我的姓名是:张三")
    time.sleep(2)


show_info()

运行结果:

我的姓名是:张三
装饰器打印执行时间为:2.00051

被装饰函数有返回值

被装饰函数有返回值,那么在设计装饰器的时候,就应该有变量进行接收,然后再将该返回值返回给调用者

例1:

import time

def timer(func):
    def inner():
        start_time = time.time()
        inner_ret = func()              # 调用原函数并接受返回值
        end_time = time.time()
        print(f'装饰器打印执行时间为:{round(end_time - start_time, 5)}')
        return inner_ret                # 将调用原函数的返回值返回给调用者
    return inner            # 闭包,返回内层函数的引用


@timer          # show_info = timer(show_info)第一个show_info是一个新的变量,第二个show_info的函数名,@timer是show_info = timer(show_info)的简写,官方叫做语法糖
def show_info():
    print(f"我的姓名是:张三")
    time.sleep(2)
    return 'show_info函数的返回值'


ret = show_info()           # ret接受的是inner的返回值inner_ret
print(ret)

我的姓名是:张三
装饰器打印执行时间为:2.00168
show_info函数的返回值

被装饰函数有参数

被装饰函数有参数,由于实际调用的时候,掉的是闭包中的内部函数,所以内部函数相应的也要设计成跟原函数一样的带参数

例1:

import time

def timer(func):
    def inner(name):               # 设计时需要添加参数
        start_time = time.time()
        inner_ret = func(name)              # 调用原函数indxe,传入参数并接受返回值
        end_time = time.time()
        print(f'装饰器打印执行时间为:{round(end_time - start_time, 5)}')
        return inner_ret                # 将调用原函数的返回值返回给调用者
    return inner            # 闭包,返回内层函数的引用


@timer          # show_info = timer(show_info)第一个show_info是一个新的变量,第二个show_info的函数名,@timer是show_info= timer(show_info)的简写,官方叫做语法糖
def show_info(name):
    print(f"我的姓名是:{name}")
    time.sleep(2)
    return 'show_info函数的返回值'


ret = show_info('张三')       # 相当于ret = inner('张三')
print(ret)

我的姓名是:张三
装饰器打印执行时间为:2.00031
show_info函数的返回值

标准装饰器

由于被装饰函数的参数个数不确定,所以我们在设计装饰器时,内部函数的参数个数就无法确定,因此要设计成不定长的形式

例1:

import time

def timer(func):
    def inner(*args, **kwargs):               # 设计时需要添加参数
        start_time = time.time()
        inner_ret = func(*args, **kwargs)     # 调用原函数indxe,传入参数并接受返回值
        end_time = time.time()
        print(f'装饰器打印执行时间为:{round(end_time - start_time, 5)}')
        return inner_ret                # 将调用原函数的返回值返回给调用者
    return inner            # 闭包,返回内层函数的引用


@timer          # show_info = timer(show_info)第一个show_info是一个新的变量,第二个show_info的函数名,@timer是show_info= timer(show_info)的简写,官方叫做语法糖
def show_info(name, age):
    print(f"我的姓名是:{name}, 今年{age}岁")
    time.sleep(2)
    return 'show_info函数的返回值'


ret = show_info('张三', 25)
print(ret)

我的姓名是:张三, 今年25岁
装饰器打印执行时间为:2.0017
show_info函数的返回值

特别注意

在标准装饰器中,def inner(*args, **kwargs): 中的 * 在函数 定义 的时候是将传入函数的参数聚合成一个元素,在 调用函数inner_ret = func(*args, **kwargs) 的时候 * 的作用是将一个可迭代的对象进行打散,即将变量 args或kwargs 打散,拆分成一个个要传入的实参

标准装饰器模板:

def decorator(real_func_name):
    def inner(*args, **kwwargs):
        '''调用装饰器访问函数前要执行的操作'''
        ret = real_func_name(*args, **kwwargs)
         '''调用装饰器访问函数后要执行的操作'''
        return ret
   	return inner

装饰器的应用

装饰器一般用于登录验证和日志

例1:

def login():
    name = input('请输入用户名:')
    pwd = input('请输入密码:')
    login_status['name'] = name
    if pwd == '123456':
        login_status['status'] = True
        return 1
    else:
        return 0


login_status = {
    'name': None,
    'status': False
}


def decorator(func_name):
    def inner(*args, **kwargs):
        if login_status['status']:
            ret = func_name(*args, **kwargs)
            return ret
        else:
            ret = login()
            if ret:
                ret = func_name()
                return ret
            else:
                print('登录失败')

    return inner


@decorator
def index():
    print("index页面")

@decorator
def logger():
    print("logger页面")

# 只有登录成功后才会执行函数,并打印信息
index()
logger()

请输入用户名:张三
请输入密码:123456
index页面
logger页面