python装饰器

装饰器

  特征

    器:指的是工具。

    装饰:给被装饰对象添加额外的功能。

  原则

    开放封闭原则

      开放:对扩展开放。
      封闭:对修改封闭。

  核心思想

    在不改变被"装饰对象内部代码"和"原有调用方式"的基础之上添加额外功能。

    在满足上述条件的情况下添加计算运行时间功能。

 

装饰器简易版本

  装饰器的本来需求是要不改变原有的调用方式,因此可以使用将装饰器的函数名赋给和原来函数名相同的新变量名,来达成偷梁换柱的目的。

  此时的index调用的其实是get_time2函数。

 

 

解决参数问题

  上述的程序只能用于无参数的函数,当函数需要传入参数时就会报错,因此还需要解决函数传入参数的问题。

  可以利用*args和**kwargs可接受所有参数的特性来解决参数问题。

 

 

解决返回值问题

  在解决了参数问题后,还有返回值的问题,当原函数有返回值时,上述的程序是无法返回的。因此还要添加返回值。

  需要在装饰器内定义一个变量来接收原函数的返回值,然后在返回该变量。

  

 

认证装饰器

  通过装饰器可以添加一个认证功能,利用全局变量,可以达成只用登录一次就使用全部功能d效果。

复制代码
is_login = {'is_login': False}  
def login(func):
    def login1(*args, **kwargs):
        if is_login.get('is_login'):
            res = func(*args, **kwargs)
            return res
        username = input('请输入用户名:')
        password = input('请输入密码:')
        if username == 'tom' and password == '123':
            is_login['is_login'] = True
            res = func(*args, **kwargs)
            return res
        else:
            print('用户名或密码错误')
    return login1
def index():
    print('登录成功')
def index1():
    print('第二个功能')
index = login(index)
index1 = login(index1)
index()
index1()
复制代码

  效果为当第一次输入正确后,就不需要再登录,当第一登录失败后则需在此登录。

 

 

装饰器模板

  通过上述的例子,可以推导出装饰器的一个万用模板。

  利用该模板可以轻松完成装饰器。

def outer(func):
    def inner(*args, **kwargs):
        print('执行函数之前可以添加的额外功能')
        res = func(*args, **kwargs)  # 执行被装饰的函数
        print('执行函数之后可以添加的额外功能')
        return res  # 将被装饰函数执行之后的返回值返回
    return inner

 

装饰器语法糖

  在完成装饰器后,可以使用装饰器语法糖(@函数名)来代替index = login(index)这句话,来使装饰器的调用更接近原函数。

  语法糖的语法规范:紧贴在需要装饰的函数上方。

  语法糖的内部原理:将紧贴的函数名作为参数传给装饰器函数调用。

 

复制代码
import time
def get_time1(func):
    def get_time2(*args, **kwargs):
        start_time = time.time()
        res = func(*args, **kwargs)
        end_time = time.time()
        print('运行时间%s' % (end_time - start_time))
        return res
    return get_time2
@get_time1
def index(name):
    time.sleep(1)
    print('%s在测量时间' % name)
    return 'time'
print(index('tom'))
复制代码

 

 

 

双层语法糖

  语法糖可以 多个叠加,当函数上方两个以上的语法糖时,他相当于是把下方的函数作为参数依次向上传,在运行时则是从上向下运行。

复制代码
import time

is_login = {'is_login': False}


def get_time1(func):
    def get_time2(*args, **kwargs):
        start_time = time.time()
        res = func(*args, **kwargs)
        end_time = time.time()
        print('运行时间%s' % (end_time - start_time))
        return res

    return get_time2


def login1(func):
    def login2(*args, **kwargs):
        if is_login.get('is_login'):
            res = func(*args, **kwargs)
            return res
        username = input('请输入用户名:')
        password = input('请输入密码:')
        if username == 'tom' and password == '123':
            res = func(*args, **kwargs)
            return res
        else:
            print('用户名或密码错误')

    return login2


@login1
@get_time1
def index(name):
    time.sleep(1)
    print('%s在测量时间' % name)
    return 'time'


index('tom')
复制代码

 

  因为要求登录的语法糖在上方,所以会先进行登录在进行计时。结果如下:

 

 

 

 

装饰器修复技术

  我们现在使用了装饰器虽然看似调用的函数是原函数,但其实是其他的函数。为了使装饰器变得更像真的,可以使用装饰器修复技术。

  他的作用是在使用装饰器后对函数进行输出,所看到的依旧是原函数的内存地址。

 

 

有参装饰器

  在函数的模板中可以看到,双层的函数参数都是被固定的,有他们自己的功能。当我们还想往装饰器里传入参数时,就会遇到问题。

  为解决这个问题,所采取的方法是在外层再包一层函数,将参数传入这层来供内层的装饰器使用。

  此时需要的参数可以通过装饰器的语法糖来传入。

复制代码
def more(another):
    from functools import wraps
    def get_time1(func):
        @wraps(func)
        def get_time2(*args, **kwargs):
            start_time = time.time()
            res = func(*args, **kwargs)
            end_time = time.time()
            print('运行时间%s' % (end_time - start_time))
            print('需要一个外层参数%s' % another)
            return res
        return get_time2
    return  get_time1
@more('示例')
def index(name):
    time.sleep(1)
    print('%s在测量时间' % name)
    return 'time'
index('tom')
复制代码

  运行结果如下:

 

posted @   临江沂水  阅读(34)  评论(0编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示