装饰器

闭包函数

  • 1.在函数内部在定义一个函数

    2.内部函数可以使用外部函数局部名称空间的名字

    符合这两条的就被称为闭包函数

def func(name):  # 1定义函数func  # 3调用时name接收实参
    username = name  # 4将name的数据值赋值给username

    def info():  # 5定义函数info
        print(username)  # 8打印username的数据值
    # 9run:barry
    return info  # 6函数名info为返回值


res = func('barry')  # 2调用函数func,将返回值赋值给res
res()  # 7定义返回值info函数

装饰器简介

  • 什么是装饰器
在不改变装饰对象原来的'调用'与'函数体代码'的条件下修改装饰对象功能的函数,叫装饰器
  • 扩展知识
import time  # 调用time模块

print(time.time())  # 时间戳:运行时距离1970年1月1日0时0分0秒所经历的秒数
# run:1657004281.4972255

start_time = time.time()  # 将运行时间戳的时间赋值给start_time变量名
time.sleep(1)  # 让程序等待一秒
end_time = time.time()  # 将运行时间戳的时间赋值给end_time变量名
print(end_time - start_time)  # 求差可得运行第一个时间戳到第二个时间戳的时间
# run:1.0154657363891602(差不多是一秒)

装饰器推导

  • 统计函数的执行时间

    缺陷:需要反复编写待码

import time  # 调用time模块


def func():  # 定义函数func
    time.sleep(1)  # 让程序等待一秒
    print('from func')  # 函数的执行结束
    # run:from func

start_time = time.time()  # 将运行时间戳的时间赋值给start_time变量名
func()  # 调用函数func
end_time = time.time()  # 将运行时间戳的时间赋值给end_time变量名
print(end_time - start_time)  # 求差可得运行第一个时间戳到第二个时间戳的时间
# run:1.0155069828033447  # 函数funcd的执行时间
  • 将统计函数代码改为函数体代码

    缺陷:形参数不同的函数无法使用

import time  # 调用time模块


def func():  # 定义函数func
    time.sleep(1)  # 让程序等待一秒
    print('from func')  # 函数的执行结束
    # run:from func


def get_time(a):  # 定义函数且用形参接收要调用的函数名
    start_time = time.time()  # 将运行时间戳的时间赋值给start_time变量名
    a()  # 调用所需要的函数
    end_time = time.time()  # 将运行时间戳的时间赋值给end_time变量名
    print(end_time - start_time)  # 求差可得运行第一个时间戳到第二个时间戳的时间
    # run:1.0118203163146973  # 函数func的执行时间

get_time(func)  # 调用get_time函数并将func函数名传给形参
  • 使用*和**可以支持形参数不同的函数
import time  # 调用time模块


def outer(x):  # 定义函数且用形参接收要调用的函数名
    def get_time(*a, **b):  # 定义函数且用形参接收实参数据值
        start_time = time.time()  # 将运行时间戳的时间赋值给start_time变量名
        x(*a, **b)  # 调用所需要的函数,传输实参
        end_time = time.time()  # 将运行时间戳的时间赋值给end_time变量名
        print(end_time - start_time)  # 求差可得运行第一个时间戳到第二个时间戳的时间


    return get_time  # 函数名get_time为返回值


def func():  # 定义函数func
    time.sleep(1)  # 让程序等待一秒
    print('from func')  # 函数的执行结束
    # run:from func


func = outer(func)  # 调用函数outer,将返回值赋值给func
func()  # 定义返回值get_time函数
print(func)  # <function outer.<locals>.get_time at 0x000001BB681B70D0>

装饰器各种版本

import time  # 调用time模块


def outer(x):  # 定义函数且用形参接收要调用的函数名
    def get_time(*a, **b):  # 定义函数且用形参接收实参数据值
        start_time = time.time()  # 将运行时间戳的时间赋值给start_time变量名
        x(*a, **b)  # 调用所需要的函数,传输实参
        end_time = time.time()  # 将运行时间戳的时间赋值给end_time变量名
        print(end_time - start_time)  # 求差可得运行第一个时间戳到第二个时间戳的时间


    return get_time  # 函数名get_time为返回值


def func():  # 定义函数func
    time.sleep(1)  # 让程序等待一秒
    print('from func')  # 函数的执行结束
    # run:from func


def lnof(a, b):  # 定义函数lnof
    time.sleep(2)  # 让程序等待一秒
    print(a, b)  # 函数的执行结束
    # run:1 2


func = outer(func)  # 调用函数outer,将返回值赋值给func
func()  # 定义返回值get_time函数
print(func)  # <function outer.<locals>.get_time at 0x000001BB681B70D0>
lnof = outer(lnof)  # 调用函数outer,将返回值赋值给lnof
lnof(1, 2)  # 定义返回值get_time函数并将实参传给形参
print(lnof)  # <function outer.<locals>.get_time at 0x0000020092E87790>

装饰器固定模板

  • 可以直接套用的装饰器固定模板
import time  # 调用time模块


def outer(x):  # 定义函数且用形参接收要调用的函数名
    def get_time(*args, **kwargs):  # 定义函数且用形参接收实参数据值
        print()  # 行被装饰对象前可以进行额外操作
        res = x(*args, **kwargs)  # 执行被装饰函数
        print()  # 行被装饰对象后可以进行额外操作
        return res  # 返回真正的返回值

    return get_time  # 函数名get_time为返回值
  • 装饰器语法糖

    语法糖会将下面的函数名传给@后面的函数形参

'@装饰函数名'


import time  # 调用time模块


def outer(x):  # 定义函数且用形参接收要调用的函数名
    def get_time(*a, **b):  # 定义函数且用形参接收实参数据值
        start_time = time.time()  # 将运行时间戳的时间赋值给start_time变量名
        res = x(*a, **b)  # 调用所需要的函数,传输实参
        end_time = time.time()  # 将运行时间戳的时间赋值给end_time变量名
        print(end_time - start_time)  # 求差可得运行第一个时间戳到第二个时间戳的时间
        return res

    return get_time  # 函数名get_time为返回值


@outer  # 相当于func = outer(func)
def func():  # 定义函数func
    time.sleep(1)  # 让程序等待一秒
    print('from func')  # 函数的执行结束
    # run:from func


func()  # 定义返回值get_time函数
print(func)  # <function outer.<locals>.get_time at 0x000001CE84097700>
  • 让装饰器不容易被别人发现
from functools import wraps
import time  # 调用time模块


def outer(x):  # 定义函数且用形参接收要调用的函数名
    def get_time(*args, **kwargs):  # 定义函数且用形参接收实参数据值
        print()  # 行被装饰对象前可以进行额外操作
        res = x(*args, **kwargs)  # 执行被装饰函数
        print()  # 行被装饰对象后可以进行额外操作
        return res  # 返回真正的返回值

    return get_time  # 函数名get_time为返回值


@outer
def func():  # 定义函数func
    time.sleep(1)  # 让程序等待一秒
    print('from func')  # 函数的执行结束


info = func
print(info)

作业

  • 执行每个函数的时候必须先校验身份
def name(a):  # 定义name函数
    def get_time(*b, **c):  # 定义函数且用形参接收实参数据值
        while True:
            username = input('输入用户名>>>:').strip()  # 输入用户名
            password = input('输入密码>>>:').strip()  # 输入密码
            if username == 'jason' and password == '123':  # 判断用户名密码是否正确
                a(*b, **c)  # 调用所需要的函数,传输实参
                print('功能尚未开发完成\n敬请期待')

            else:
                print('用户名或密码错误')
                continue  # 用户名或密码错误重新输入

    return get_time  # 返回get_time 函数名


@name  # func = name(func)
def func():
    print('登录成功')  # 登录成功时运行


func()  # 定义返回值get_time函数
  • 提高难度
def register():
    print('注册功能')


@login_auth
def login():
    print('登录功能')


@login_auth
def transfer():
    print('转账功能')


@login_auth
def withdraw():
    print('提现功能')


register()
login()
transfer()
withdraw()



is_login = {'is_login': False, }
# 2.编写装饰器
def login_auth(func_name):
    def inner(*args, **kwargs):
        # 2.3判断全局字典is_login对应的值是否是True
        if is_login.get('is_login'):
            # 2.4直接执行被装饰函数即可
            res = func_name(*args, **kwargs)
            return res
        # 2.1假设是第一次调用 肯定需要校验用户身份
        username = input('username>>>:').strip()
        password = input('password>>>:').strip()
        if username == 'jason' and password == '123':
            res = func_name(*args, **kwargs)
            # 2.2保存用户登录的状态
            is_login['is_login'] = True
            return res
        else:
            print('权限不够 无法执行')
    return inner
posted @ 2022-07-05 22:18  无言以对啊  阅读(50)  评论(0)    收藏  举报