首页 > 编程语言 >Python高级之装饰器

Python高级之装饰器

时间:2024-05-09 15:26:27浏览次数:17  
标签:username Python 高级 check inner func time 装饰 def

【一】装饰器

【1】什么是装饰器

  • 装饰代指为被装饰对象添加新的功能,器代指器具/工具,装饰器与被装饰的对象均可以是任意可调用对象。
  • 装饰器的作用就是在不修改被装饰对象源代码和调用方式的前提下为被装饰对象添加额外的功能

【2】装饰器的用途

  • 软件包含的所有功能的源代码以及调用方式,都应该避免修改,否则一旦改错,则极有可能产生连锁反应,最终导致程序崩溃
  • 而对于上线后的软件,新需求或者变化又层出不穷,我们必须为程序提供扩展的可能性,这就用到了装饰器

【3】装饰器的分类

  • 分为有参装饰器和无参装饰器
  • 原理都是闭包函数+函数对象的组合使用

【二】无参装饰器

【1】引入

  • 添加计算执行时间的功能
import time


def timer():
    time.sleep(2)
    print("你别睡过头了")


timer()


import time

【2】直接计时

import time


def timer():
    time.sleep(2)


start_time = time.time()
timer()
end_time = time.time()
print(f"你已经睡了{end_time - start_time} 秒")
# 你已经睡了2.008584976196289 秒

【3】函数作为参数

import time


def timer():
    time.sleep(2)


def outer(func):
    start_time = time.time()
    func()
    end_time = time.time()
    print(f"你已经睡了{end_time - start_time} 秒")
    return func


outer(timer)
# 你已经睡了2.008584976196289 秒

【4】闭包函数

import time


def timer():
    time.sleep(2)


def outer(func):
    def inner():
        start_time = time.time()
        func()
        end_time = time.time()
        print(f"你已经睡了{end_time - start_time} 秒")

    return inner


inner = outer(timer)
inner()
# 你已经睡了2.008584976196289 秒
#这样我们便可以在不修改被装饰函数源代码和调用方式的前提下为其加上统计时间的功能

【5】被装饰的函数带参数会报错

import time


def timer(func):
    time.sleep(2)


def outer(func):
    def inner():
        start_time = time.time()
        func()
        end_time = time.time()
        print(f"你已经睡了{end_time - start_time} 秒")

    return inner


inner = outer(timer)
inner()
'''
Traceback (most recent call last):
  File "D:\Python\pythonProject\pythonProject1\demo7.py", line 659, in <module>
    inner()
  File "D:\Python\pythonProject\pythonProject1\demo7.py", line 651, in inner
    func()
TypeError: timer() missing 1 required positional argument: 'func'
'''

【6】无参装饰器模版

# 通过参数 func 接收外部的函数地址
def outer(func):
    def inner():
        # 第一部分:执行外部传入的函数之前执行的代码
        '''...'''
        # 第二部分:执行外部传入的函数地址
        func()
        # 第三部分:执行外部传入的函数之后执行的代码
        '''...'''
    return inner

【三】有参装饰器

【1】有参装饰器

import time


def timer(name):
    time.sleep(2)
    print(f"{name}已经进入睡觉时间")


def outer(func):
    def inner(*args, **kwargs):
        start_time = time.time()
        func(*args, **kwargs)
        end_time = time.time()
        print(f"你已经睡了{end_time - start_time} 秒")

    return inner

# 调用外层函数outer,返回了内层函数inner的地址
inner = outer(timer)
inner('ligo')
# ligo已经进入睡觉时间
# 你已经睡了2.0065224170684814 秒

【2】有参装饰器模版

# 通过参数 func接收外部的函数地址
def outer(func):
    def inner(*args, **kwargs):
        # 第一部分:执行外部传入的函数之前执行的代码
        '''...'''
        # 第二部分:执行外部传入的函数地址
        func(*args, **kwargs)
        # 第三部分:执行外部传入的函数之后执行的代码
        '''...'''
    return inner

【四】无参语法糖

【1】无装饰器参语法糖

  • 为了简洁而优雅地使用装饰器,Python提供了专门的装饰器语法来取代index=timer(index)的形式
  • 需要在被装饰对象的正上方单独一行添加@timer
  • 当解释器解释到 @timer时就会调用timer函数
  • 且把它正下方的函数名当做实参传入
  • 然后将返回的结果重新赋值给原函数名
#【1】无语法糖
import time


def outer(func):
    def inner():
        start_time = time.time()
        func()
        end_time = time.time()
        print(f"你已经睡了{end_time - start_time} 秒")

    return inner


def timer():
    time.sleep(2)


timer = outer(timer)
timer()

#【2】有语法糖
import time


def outer(func):
    def inner():
        start_time = time.time()
        func()
        end_time = time.time()
        print(f"你已经睡了{end_time - start_time} 秒")

    return inner


@outer
def timer():
    time.sleep(2)


timer()

【2】有装饰器参语法糖

import time


def outer(func):
    def inner(*args, **kwargs):
        start_time = time.time()
        func(*args, **kwargs)
        end_time = time.time()
        print(f"你已经睡了{end_time - start_time} 秒")

    return inner


@outer
def timer(name):
    time.sleep(2)
    print(f"{name}已经进入睡觉时间")


timer('ligo')

【五】有参语法糖

【1】单语法糖

import time


user_data = {'username': 'ligo'}


def check_login(func):
    def inner(*args, **kwargs):
        if user_data.get('username'):
            func(*args, **kwargs)
        else:
            print("你需要先登陆!")
    return inner


def outer(func):
    def inner(*args, **kwargs):
        start_time = time.time()
        func(*args, **kwargs)
        end_time = time.time()
        print(f"你已经睡了{end_time - start_time} 秒")

    return inner


@check_login
def timer(name):
    time.sleep(2)
    print(f"{name}已经进入睡觉时间")


timer('ligo')

【2】多语法糖

import time

user_data = {'username': 'ligo'}


def check(tag):
    if tag == 'check_login':
        def check_login(func):
            def inner(*args, **kwargs):
                if user_data.get('username'):
                    func(*args, **kwargs)
                else:
                    print("你需要先登陆!")

            return inner

        return check_login
    elif tag == 'outer':
        def outer(func):
            def inner(*args, **kwargs):
                start_time = time.time()
                func(*args, **kwargs)
                end_time = time.time()
                print(f"你已经睡了{end_time - start_time} 秒")

            return inner

        return outer


@check(tag='check_login')
@check(tag='outer')
def timer(name):
    time.sleep(2)
    print(f"{name}已经进入睡觉时间")


timer('ligo')

【3】多语法糖案例

#【1】原始方法
user_data = {'username': "dream", "password": "521"}


def check_username(func):
    # 【六】进入到 check_username 里面
    # func = check_password 里面的inner
    print('check_username')

    # 【十】调用inner
    def inner(*args, **kwargs):
        # 【十一】进来函数内容
        print('校验用户名之前')
        username = input("username :>>>> ").strip()
        if user_data.get("username") != username:
            print(f"用户名错误!")
        # 【十二】调用 func 函数 check_password 里面的inner
        func(*args, **kwargs)
        # 【十七】执行完  check_password 里面的inner 回来
        print('校验用户名之后')

    # 【七】返回inner
    return inner


def check_password(func):
    # 【二】调用 check_password 进来
    print("check_password")

    # 【十三】来到 check_password 里面的 inner 是从 check_username 的inner来的
    def inner(*args, **kwargs):
        # 【十四】进入到函数内部
        print('校验密码之前')
        password = input("password :>>>> ").strip()
        if user_data.get("password") != password:
            print(f"密码错误!")
        # 【十五】进入到func函数内部 -- 真正的 transform
        func(*args, **kwargs)
        # 【十六】走完 transform 回来继续走
        print('校验密码之后')

    # 【三】返回 inner
    return inner


def transform():
    print("这是主函数的 transform")


# 原来的方法 ---> 校验用户名和密码
# 先校验用户名  后校验密码

# 【一】进入到 check_password 函数里面 ---> 获取到返回值 这个返回值就是 check_password 藜麦你的inner
# 【四】transform 就是返回的inner 的函数内存地址
transform = check_password(transform)  # 在 check_password 里面的 inner 里面的 func 是我上面的 transform 函数
# 【五】进入到 check_username 函数里面
# 【八】transform 就是 check_username 里面返回的inner
transform = check_username(transform)  # transform 是因为我要先校验用户名 , 必须先触发 check_username 里面的 inner
# 【九】调用 inner
transform()
# 【十九】结束

# check_password
# check_username
# 校验用户名之前
# 校验密码之前
# 这是主函数的 transform
# 校验密码之后
# 校验用户名之后

#【2】使用语法糖
user_data = {'username': "dream", "password": "521"}


def check_username(func):
    # 【六】进入到 check_username 里面
    # func = check_password 里面的inner
    print('check_username')

    # 【十】调用inner
    def inner(*args, **kwargs):
        # 【十一】进来函数内容
        print('校验用户名之前')
        username = input("username :>>>> ").strip()
        if user_data.get("username") != username:
            print(f"用户名错误!")
        # 【十二】调用 func 函数 check_password 里面的inner
        func(*args, **kwargs)
        # 【十七】执行完  check_password 里面的inner 回来
        print('校验用户名之后')

    # 【七】返回inner
    return inner


def check_password(func):
    # 【二】调用 check_password 进来
    print("check_password")

    # 【十三】来到 check_password 里面的 inner 是从 check_username 的inner来的
    def inner(*args, **kwargs):
        # 【十四】进入到函数内部
        print('校验密码之前')
        password = input("password :>>>> ").strip()
        if user_data.get("password") != password:
            print(f"密码错误!")
        # 【十五】进入到func函数内部 -- 真正的 transform
        func(*args, **kwargs)
        # 【十六】走完 transform 回来继续走
        print('校验密码之后')

    # 【三】返回 inner
    return inner


# 装饰器语法糖谁在最上面就先校验谁
@check_username  # transform = check_username(transform) = check_username(check_password(transform))
@check_password  # transform = check_password(transform)
def transform():
    print("这是主函数的 transform")


# 原来的方法 ---> 校验用户名和密码
# 先校验用户名  后校验密码

# 【一】进入到 check_password 函数里面 ---> 获取到返回值 这个返回值就是 check_password 藜麦你的inner
# 【四】transform 就是返回的inner 的函数内存地址
# transform = check_password(transform)  # 在 check_password 里面的 inner 里面的 func 是我上面的 transform 函数
# 【五】进入到 check_username 函数里面
# 【八】transform 就是 check_username 里面返回的inner
# transform = check_username(transform)  # transform 是因为我要先校验用户名 , 必须先触发 check_username 里面的 inner
# 【九】调用 inner
transform()
# 【十九】结束

# check_password
# check_username
# 校验用户名之前
# 校验密码之前
# 这是主函数的 transform
# 校验密码之后
# 校验用户名之后

【六】综合练习

【1】需求

# 定义一个数据字典存储用户数据
# 分别校验用户名和密码
# 分别是两个装饰器
# 一个负责校验用户名是否存在
# 只有符合上一个装饰器的条件才能走到下一个装饰器

【2】套两层

user_data = {'username': 'ligo', 'password': '123'}


def get_username(func):
    def inner(*args, **kwargs):

        username_input = input("请输入用户名:").strip()
        if username_input == user_data.get('username'):
            print('用户名正确')
            func(*args, **kwargs)
        else:
            print('用户名错误')
    return inner


def get_password(func):
    def inner(*args, **kwargs):
        password_input = input("请输入密码:").strip()
        if password_input == user_data.get('password'):
            print('密码正确')
            func(*args, **kwargs)
        else:
            print('密码错误')
    return inner


def transform(username, money):
    print(f"{username}转账{money}")


transform = get_password(transform)
# password 的 inner
transform = get_username(transform)
# username 的 inner
transform('ligo', 1000)

【3】双层语法糖

user_data = {'username': 'ligo', 'password': '123'}


def get_username(func):
    def inner(*args, **kwargs):

        username_input = input("请输入用户名:").strip()
        if username_input == user_data.get('username'):
            print('用户名正确')
            func(*args, **kwargs)
        else:
            print('用户名错误')
    return inner


def get_password(func):
    def inner(*args, **kwargs):
        password_input = input("请输入密码:").strip()
        if password_input == user_data.get('password'):
            print('密码正确')
            func(*args, **kwargs)
        else:
            print('密码错误')
    return inner


@get_username
@get_password
def transform(username, money):
    print(f"{username}转账{money}")


transform('ligo', 1000)

【4】双层有参语法糖

user_data = {'username': 'ligo', 'password': '123'}


def check_user(tag):
    if tag == 'get_username':
        def get_username(func):
            def inner(*args, **kwargs):
                username_input = input("请输入用户名:").strip()
                if username_input == user_data.get('username'):
                    print('用户名正确')
                    func(*args, **kwargs)
                else:
                    print('用户名错误')

            return inner

        return get_username
    elif tag == 'get_password':
        def get_password(func):
            def inner(*args, **kwargs):
                password_input = input("请输入密码:").strip()
                if password_input == user_data.get('password'):
                    print('密码正确')
                    func(*args, **kwargs)
                else:
                    print('密码错误')

            return inner

        return get_password


@check_user(tag='get_username')
@check_user(tag='get_password')
def transform(username, money):
    print(f"{username}转账{money}")


transform('ligo', 1000)

【七】伪装装饰器

【1】查看装饰器(help)

  • 可以使用help(函数名)来查看函数的文档注释,本质就是查看函数的doc属性
import time


def outer(func):
    def inner(*args, **kwargs):
        start_time = time.time()
        func(*args, **kwargs)
        end_time = time.time()
        print(f"你已经睡了{end_time - start_time} 秒")

    return inner


@outer
def timer(name):
    """
      timer page function
      :param name: str
      :return: None
    """
    time.sleep(2)
    print(f"{name}已经进入睡觉时间")


print(help(timer))
'''
Help on function inner in module __main__:

inner(*args, **kwargs)

None
'''

【2】伪装装饰器(functools)

  • functools模块下提供一个装饰器wraps专门来帮助我们实现保留原函数属性
import time
from functools import wraps


def outer(func):
    @wraps(func)
    def inner(*args, **kwargs):
        start_time = time.time()
        func(*args, **kwargs)
        end_time = time.time()
        print(f"你已经睡了{end_time - start_time} 秒")

    return inner


@outer
def timer(name):
    """
      timer page function
      :param name: str
      :return: None
    """
    time.sleep(2)
    print(f"{name}已经进入睡觉时间")


print(help(timer))
'''
Help on function timer in module __main__:

timer(name)
    timer page function
    :param name: str
    :return: None

None
'''

标签:username,Python,高级,check,inner,func,time,装饰,def
From: https://www.cnblogs.com/ligo6/p/18180004

相关文章

  • Python高级之生成器
    【一】什么是生成器Python中的生成器是一种特殊的迭代器可以在需要时生成数据,而不必提前从内存中生成并存储整个数据集通过生成器,可以逐个生成序列中的元素,而无需一次性生成整个序列【二】生成器的创建方式【1】列表推导式#列表生成式生成列表num_list=[iforiinra......
  • Python高级之迭代器
    【一】迭代器介绍迭代器就是迭代取值的工具,而迭代是重复反馈过程的活动其目的通常是为了逼近所需的目标或结果,而每一次迭代得到的结果会作为下一次迭代的初始值#只会重复让你输入信息,并不是迭代过程whileTrue:msg=input("请输入信息:").strip()print(msg)#下......
  • Python高级之【补充】算法
    【一】二分法【1】介绍二分法也称为折半法,是一种在有序数组中查找特定元素的搜索算法【2】思路首先,从数组的中间元素开始搜索,如果该元素正好是目标元素,则搜索过程结束,否则执行下一步如果目标元素大于/小于中间元素,则在数组大于/小于中间元素的那一半区域查找,然后重复步骤......
  • Python高级之常用的内置函数
    【一】什么是内置函数内置函数就是Python给你提供的,拿来直接用的函数目前共有68个内置函数Built-inFunctionsAabs()aiter()all()any()anext()ascii()Bbin()bool()breakpoint()bytearray()bytes()Ccallable()chr()classmethod()compile()complex()Ddelatt......
  • Python高级之模块与包
    【一】模块介绍【1】什么是模块在Python中,一个py文件就是一个模块,文件名为xxx.py模块名则是xxx,导入模块可以引用模块中已经写好的功能使用模块既保证了代码的重用性,又增强了程序的结构性和可维护性另外除了自定义模块外,我们还可以导入使用内置或第三方模块提供的现成功能......
  • 《最新出炉》系列入门篇-Python+Playwright自动化测试-45-鼠标操作-下篇
    1.简介鼠标为我们使用电脑提供了很多方便,我们看到的东西就可以将鼠标移动过去进行点击就可以打开或者访问内容,当页面内容过长时,我们也可以使用鼠标滚轮来实现对整个页面内容的查看,其实playwright也有鼠标操作的方法。上一篇文章中已经讲解过鼠标的部分操作了,今天宏哥在这里将剩下......
  • Python高级之函数参数进阶Optional
    【一】引言在Python3.5版本后引入的typing模块为Python的静态类型注解提供了支持。这个模块在增强代码可读性和维护性方面提供了帮助。本文将深入探讨typing模块,介绍其基本概念、常用类型注解以及使用示例,以帮助读者更全面地了解和应用静态类型注解。【二】基本类型注解【......
  • Python高级之名称空间和作用域
    【一】名称空间【1】什么是名称空间名称空间就是存放函数名与函数值对应关系的地方内存空间就是申请一块内存空间,然后将函数值放到内存空间里再将变量名和变量值绑定存到名称空间里程序执行期间最多会存在三种名称空间【2】内置名称空间会跟着python解释器的启动而生成,......
  • Python高级之匿名函数
    【一】匿名函数的定义在Python里有两类函数:用def关键词定义的正规函数用lambda关键词定义的匿名函数lambda参数:表达式lambda:定义匿名函数的关键词。函数参数它们可以是位置参数、默认参数、关键字参数表达式,输入函数参数,输出一些值,表达式本身结果就是返回......
  • Python高级之函数对象与闭包函数
    【一】函数对象函数对象是指函数可以被当成数据来处理,python中一切皆为对象【1】函数可以被引用defadd(a,b):returna+bres=add(3,4)print(res)#7【2】函数作为容器类型的元素defadd(a,b):returna+bnum_list=[add,1]res=num_list[0......