史上最详细的Python装饰器解释

史上最详细的Python装饰器解释

一个装饰器装饰一个函数

在Python中有个概念叫装饰器,很多初学者最初听到这个名词的时候可能都会一脸懵逼,包括我之前也是,那么什么是装饰器呢。

装饰器本质就是函数,作用是装饰其它函数,给其它函数增加附加功能,提高代码复用,减少代码量。
实现装饰器的条件:

  1. 存在闭包现象
  2. 被装饰的函数做装饰器函数的参数

关于闭包在我的另一篇文章中会有详细介绍

def decorator(func):
	print("这是一个装饰器")
	def wrapper(*args,**kwgs):
		print("开始装修")
		func()
		print("装修完毕")
	return wrapper
	
@decorator
def house():
	print("我是毛坯房")
house()

运行结果:
在这里插入图片描述

在这段代码中,decorator函数就是一个装饰器,house函数就是一个被装饰函数,我们通过@decorator来实现decorator函数对house函数的装饰。通过运行程序我们发现我们调用的是house()函数,但输出结果却将decorator函数及其嵌套函数wrapper的内容也打印了出来,这又是为什么呢?

其实主要原因就是在于@decorator,Python解释器遇到@decorator后,会自动将被装饰函数house作为实参传给decorator函数的形参func(在Python中,万物皆对象,凡是对象就会有引用,此处就是将house的引用传给了func),也就是执行func=house,然后程序就会进入decorator函数内部,执行decorator函数,也就打印出了"这是一个装饰器",然后将wrapper函数return给house,也就是执行house=wrapper,注意,这个时候并没有调用wrapper函数内的内容,然后我们通过house()执行函数wrapper(因为此时house已经变成了wrapper,所以我们实际上执行的是wrapper函数),然后我们进入wrapper函数内部,逐步执行其中的内容,也就是先执行print(“开始装修”),然后执行fun(),此时的fun已经变成了原来的house,所以我们实际上执行的原来的house函数,也就是执行了print(“我是毛坯房”),最后执行print(“装修完毕”),程序运行结束,也就是说如果我们不调用house(),程序也会自动调用decorator函数输出"这是一个装饰器"
在这里插入图片描述

def decorator(func):#func用来接收被装饰函数
	print("这是一个装饰器")
	def wrapper(*args,**kwgs):#接收house函数中的参数,如果没有则不接收
		print("开始装修")
		func()
		print("装修完毕")
	return wrapper
	
@decorator
def house():
	print("我是毛坯房")

运行结果:

在这里插入图片描述
而wrapper中的参数又是干嘛用的呢,其实就是当我们定义被装饰函数时,如果在被装饰函数中需要传参,也就是在调用house时需要传参进去,因为此时house已经成了wrapper,所以我们传的参数就被wrapper中的参数接收了,我们可以在wrapper中调用传入的参数

多个装饰器装饰同一个函数

当多个装饰器装饰同一个函数时,其实原理跟上面所讲的也是一样的,装饰的顺序先用离被装饰函数最近的那个装饰器来装饰,下面用一个例子来说明

def decorator1(func1):
	print("这是第一个装饰器")
	def wrapper1(*args,**kwgs):
		print("开始装修")
		func1()
		print("装修完毕")
	return wrapper1
def decorator2(func2):
	print("这是第二个装饰器")
	def wrapper2(*args,**kwgs):
		print("开始第二次装修")
		func2()
		print("第二次装修完毕")
	return wrapper2
@decorator2	
@decorator1
def house():
	print("我是毛坯房")
house()

运行结果:
在这里插入图片描述

我直接画出流程图来解释这段代码的执行过程
在这里插入图片描述

装饰器带参数

当装饰器需要传参进去时,那么我们就必须要定义三层嵌套结构,并且返回两次

def outer(a):#第一层用来接收装饰器的参数
	def decorator(func):#第二层接收被装饰函数
		print("这是一个装饰器")
		def wrapper(*args,**kwgs):#第三层用来接收被装饰函数的参数
			print("开始装修",a)
			func()
			print("装修完毕")
		return wrapper
	return decorator
	
@outer("别墅")
def house():
	print("我是毛坯房")
house()

运行结果
在这里插入图片描述

当我们使用@outer(“别墅”)时,"别墅"会传给参数a,然后return decorator,然后后面的执行过程就跟前面所说的一样了,既会使用decorator函数去装饰house函数

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值