python——装饰器相关内容

下面将依次介绍装饰器是如何来的,装饰器如何装饰带返回值的函数,如何装饰带参数的函数,多个装饰器如何装饰同一个函数以及什么叫做带参数装饰器。

'''
    假设我们想要对于我们写的函数进行计时(这个函数可以很多很多个),那么我们如何做呢?下面是一种方法
'''
import time

def timmer(function):  # 这就是装饰器函数
    def inner():
        start = time.time()
        function()  # 这就是被装饰的函数
        end = time.time()
        print(end - start)
    return inner # 注意这里是返回内部函数名,不带括号

def func():  #
    print("Hello Python")

func = timmer(func)
func()  # 注意这里的func()执行的其实是inner函数

# 通过上面这种方法,我们没有修改函数的调用方式,去在原有函数的基础上添加了一些功能,这就是装饰器的一种粗略的模型。
'''
装饰器原则:开放封闭原则
    封闭:对修改是封闭的(相当于禁止在函数修改任何东西,即使是添加一个变量名)
    开放:对扩展是开放的
装饰器的作用:不想修改函数的调用方式,但是还想在原来的函数前后添加功能
'''
# 在上面的方法中,我们的func函数并没有返回值,但是通常来说,函数都是有返回值的,上面的方法并不能让我们获得func()函数的返回值

def timmer(function):  # 这就是装饰器函数
    def inner():
        start = time.time()
        function()  # 这就是被装饰的函数
        end = time.time()
        print(end - start)
    return inner # 注意这里是返回内部函数名,不带括号

@timmer  # python中的语法糖 @装饰器函数名   这里@timmer就相当于执行了 func = timmer(func) @下面紧跟着的就是被装饰函数
def func():  #
    print("Hello Python")
    return '你好,世界'

# func = timmer(func)
a = func()  # 注意这里的func()执行的其实是inner函数
print(a)


#-----------------------------------------------------------------------------------------------------------
# 那么如何得到func函数的返回值呢?其实只要在inner函数里添加一个接收func函数返回值的变量,并将该变量返回即可

def timmer(function):  # 这就是装饰器函数
    def inner():
        start = time.time()
        ret = function()  # 这就是被装饰的函数
        end = time.time()
        print(end - start)
        return ret
    return inner # 注意这里是返回内部函数名,不带括号

@timmer  # python中的语法糖 @装饰器函数名   这里@timmer就相当于执行了 func = timmer(func) @下面紧跟着的就是被装饰函数
def func():  #
    print("Hello Python")
    return '你好,世界'
a = func()  # 注意这里的func()执行的其实是inner函数
print(a)
# 上面就是装饰带返回值函数的装饰器
#-----------------------------------------------------------------------------------------------------------
# 下面是装饰带参数函数的装饰器
def timmer(function):  # 这就是装饰器函数
    def inner(a):
        start = time.time()
        ret = function(a)  # 这就是被装饰的函数
        end = time.time()
        print(end - start)
        return ret
    return inner # 注意这里是返回内部函数名,不带括号

@timmer  
def func(a):  #
    print("Hello Python", a)
    return '你好,世界'
a = func(a)     # 注意这里的func()执行的其实是inner函数
print(a)
#-----------------------------------------------------------------------------------------------------------
# 上面只是一个函数并且只有一个参数,那么如果有两个函数,并且是关键字传参等,那么上面这种形式就不行了,下面是这种方法的应对形式
def timmer(function):  # 这就是装饰器函数
    def inner(*args, **kwargs):
        start = time.time()
        ret = function(*args, **kwargs)  # 这就是被装饰的函数
        end = time.time()
        print(end - start)
        return ret
    return inner # 注意这里是返回内部函数名,不带括号

@timmer  # python中的语法糖 @装饰器函数名   这里@timmer就相当于执行了 func = timmer(func) @下面紧跟着的就是被装饰函数
def func(a):
    print("Hello Python", a)
    return '你好,世界'

@timmer
def func1(a, b):
    print("Hello Python", a, b)
    return '你好'

# func = timmer(func)
a = func(1)     # 注意这里的func()执行的其实是inner函数
b = func1(1, 2)
print(a)
print(b)

#=======================================================================================================================#
'''
上面就是装饰器的形成过程,下面是装饰器的固定形式
'''
def wrapper(function):  # 这就是装饰器函数,function是被装饰的函数
    def inner(*args, **kwargs):
        '''这里写被装饰函数之前要做的事'''
        ret = function(*args, **kwargs)  # 这就是被装饰的函数
        '''这里写被装饰函数之后要做的事'''
        return ret
    return inner # 注意这里是返回内部函数名,不带括号

@wrapper  # 等价于 func = wrapper(func)
def func(a):
    '''这是一个func函数'''
    print("Hello Python", a)
    return '你好,世界'

print(func.__name__) # __name__打印函数名,这里打印的是inner,因为经过装饰器装饰后func引用的函数已经不再是原函数了
print(func.__doc__) # 打印文档注释

#=======================================================================================================================#
# 对于被装饰函数,我们不想改变其引用的函数,即我们原本的func函数在被装饰后应该依然是func函数名指的依然是原本的函数,而不是inner函数,那么我们应该怎么做呢?
# 很简单,我们只需要给inner函数使用wraps装饰器装饰一下即可
from functools import wraps

def wrapper(function):  # 这就是装饰器函数,function是被装饰的函数
    @wraps(function)  # 带参数的装饰器
    def inner(*args, **kwargs):
        '''这里写被装饰函数之前要做的事'''
        ret = function(*args, **kwargs)  # 这就是被装饰的函数
        '''这里写被装饰函数之后要做的事'''
        return ret
    return inner # 注意这里是返回内部函数名,不带括号

@wrapper
def func(a):
    '''这是一个func函数'''
    print("Hello Python", a)
    return '你好,世界'

print(func(1))
print(func.__name__) # __name__打印函数名,这里打印的就是原先的func了
print(func.__doc__) # 打印 这是一个func函数

#=======================================================================================================================#
# 对于多个装饰器装饰一个函数时

def wrapper1(function):
    print("装饰器1")
    def inner(*args, **kwargs):
        print("inner1")
        return function(*args, **kwargs)
    return inner

def wrapper2(function):
    print("装饰器2")
    def inner(*args, **kwargs):
        print("inner2")
        return function
    return inner

@wrapper1
@wrapper2
def func():
    print("func函数")
func()
# 打印的结果是: 当多个装饰器装饰一个函数时,执行时的顺序是:最先装饰的装饰器,最后一个执行。它遵循了先进后出这样一个规则
# 装饰器2
# 装饰器1
# inner1
# inner2

#=======================================================================================================================#
# 带参数的装饰器(即三层装饰器)
FLAG = True  # 设置全局变量,控制装饰器是否工作
def wrapper_out(flag):
    def wrapper(function):
        def inner(*args, **kwargs):
            if flag: # 当flag为True 即全局的FLAG为True时才运行装饰器扩展的功能
                '''这里写装饰器扩展的功能'''
                print("装饰器工作区域")
                rec = function(*args, **kwargs)
                return rec
            else:
                return function(*args, **kwargs)
        return inner
    return wrapper

@wrapper_out(FLAG) # 这里先运行 wrapper_out(FLAG) 相当于先调用了wrapper_out函数,在@ 即 先wrapper = wrapper_out(FLAG) 再 func = wrapper(func)
def func():
    return "你好,python"

@wrapper_out(FLAG)
def func2():
    return "你好,java"

print(func())
print(func2())
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值