Python:装饰器的用法及原理解析

一.什么是装饰器

● 在不改变原有函数代码的前提下,为函数增添功能

·

二. 装饰器的用法

● 先定义要为函数增添的功能代码并封装在一个闭包(“闭包”详情见我上一条博客)里,在为要增添功能的函数上加上 @闭包函数名

例:

# 通用装饰器
def set_fun(fun):
	def call_fun(*args, **kwargs):
		print("要增添的功能")
		# 当函数test()有返回值时,这里fun(*args, **kwargs)加return为了接收返回值并返回给call_fun(*args, **kwargs)
		return fun(*args, **kwargs)
	return call_fun

# 装饰器
@set_fun
def test():
	print("test函数的功能")

test()

>>>
>要增添的功能
>test函数的功能

·

三. 装饰器的原理

def set_fun(fun):
	def call_fun(*args, **kwargs):
		print("要增添的功能")
		return fun(*args, **kwargs)
	return call_fun
	
@set_fun
def test():
	print("test函数的功能")	
	
test()

>>>
>要增添的功能
>test函数的功能
                                                         ||(等价于)
def set_fun(fun):
	def call_fun(*args, **kwargs):
		print("要增添的功能")
		return fun(*args, **kwargs)
	return call_fun
	
def test():
	print("test函数的功能")	

test = set_fun(test)
test()

>>>
>要增添的功能
>test函数的功能

·

解析:

在这里插入图片描述
从图中可以看出,图中的test已经指向了函数set_fun(test),所以最下面执行的 test() 调用的已经不是def test()里的内容,而是def set_fun(test)里的内容。而call_fun()函数里面的fun()已经指向了def test()函数的内容。

因此

@set_fun 等价于 test = set_fun(test)

·

● 同一个闭包函数,对不同函数加装饰器,每一个装饰器都创建一个新的闭包内存空间,不会指向同一个闭包内存空间

例:

def set_fun(fun):
	def call_fun(*args, **kwargs):
		print("要添加的功能")
		return fun(*args, **kwargs)
	return call_fun

@set_fun
def test1(num):
	print("test1的功能%d" % num)

@set_fun
def test2(num):
	print("test2的功能%d" % num)
	
test1(100)
test2(200)

>>>
>要添加的功能
test1的功能100
要添加的功能
test2的功能200

解析:
在这里插入图片描述

如图,当给函数test2加上装饰器时,闭包函数set_fun()并不会再去指向红色方框,而是会重新创建一个内存空间,指向绿色方框。

·

·

四. 多个装饰器对同一个函数装饰

代码实例:

def set_func_01(func):
    print("這是裝飾器1") 
    def call_func(*args, **kwargs):
        print("添加裝飾器1的功能") 
        return func(*args, **kwargs)
    return call_func

def set_func_02(func):
    print("這是裝飾器2")
    def call_func(*args, **kwargs):
        print("添加裝飾器2的功能")
        return func(*args, **kwargs)
    return call_func

@set_func_01 # 等價與test = set_func_01(test)
@set_func_02 # 等價與test = set_func_02(test)
def test():
    print("---tesst---")

test()

实验结果:
在这里插入图片描述

·

解析:

注:当多个装饰器对同一个函数进行装饰时,在下面的先装饰,在上面的先运行功能

代码从上而下读取运行,当读到@set_func_01时,下面不是函数而是@set_func_02,所以代码会先跳过第一个装饰器,运行@set_func_02,发现下面是函数可以运行装饰器了
👇

在这里插入图片描述
·

·

实例演练:

代码:

def add_line(func):
    def call_func(*args, **kwargs):
        return "<td>"+func(*args, **kwargs)+"</td>"
    return call_func

def add_title(func):
    def call_func(*args, **kwargs):
        return "<h1>"+func(*args, **kwargs)+"</h1>"
    return call_func

@add_line
@add_title
def test():
    return "haha"

print(test())

实验结果:
在这里插入图片描述

·

解析:
在这里插入图片描述

·

注:多个装饰器同时装饰一个函数时,在下面的先装饰,在上面的先调用

·

·

五. 对装饰器传入参数

当用同一个装饰器对不同函数进行装饰时,想让装饰器为不同的函数增加不同的功能,则需要给装饰器传参数解决

代码实例:

def set_level(level_num):
    def set_func(func):
        def call_func(*args, **kwargs):
            if level_num == 1:
                print("增添功能1")
            elif level_num == 2:
                print("增添功能2")
            return func(*args, **kwargs)
        return call_func
    return set_func


@set_level(1)
def test1():
    print("----test1----")

@set_level(2)
def test2():
    print("----test2----")

test1()
test2()

实验结果:
在这里插入图片描述
·

解析:

当对装饰器传入参数后,会将参数带入装饰器后用所返回的对象进行装饰。
所以这里需要在两层函数闭包外再加一层函数,用来传入参数并返回两层闭包函数的应用。

  • 6
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

此时一位小白路过

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值