python 装饰器详解

1、闭包

要想了解装饰器,首先要了解一个概念,闭包。什么是闭包?一句话说就是,在函数中再嵌套一个函数,并且引用外部函数的变量,这就是一个闭包了。下面给出一个闭包的代码:

def outer(x):
    def inner(y):
        return x + y
    return inner

print(outer(6)(5))
-----------------------------
输出结果:11

如代码所示,在outer函数内,又定义了一个inner函数,并且inner函数又引用了外部函数outer的变量x,这就是一个闭包了。在输出时,outer(6)(5),第一个括号传进去的值返回inner函数,其实就是返回6 + y,所以再传第二个参数进去,就可以得到返回值,6 + 5。

2、装饰器

装饰器就是一个闭包,装饰器是闭包的一种应用。什么是装饰器呢,**简言之,python装饰器就是用于拓展原来函数功能的一种函数,这个函数的特殊之处在于它的返回值也是一个函数,使用python装饰器的好处就是在不用更改原函数的代码前提下给函数增加新的功能。**使用时,再需要的函数前加上@demo即可。

现在给你一个函数,在不修改源码的情况下。实现在函数执行前和执行后分别输入"before"和"after"。

def func():
	print("我是func函数")
	va1ue(11,22,33,44)
	return value

result func()
print(result)

2.1、第一次比较

正常实现

def func():
	print('before') #加上执行前的before

	print("我是func函数")
	va1ue(11,22,33,44)
	return value

	print('after') #加上执行后的after
result func()
print(result)

闭包实现

def func():
	print("我是func函数")
	va1ue(11,22,33,44)
	return value

def outer(origin):
	def inner():
		print('before') #加上执行前的before
		res = origin() #调用原来的func函数
		print('after') #加上执行后的after
		return res
	return inner

func = outer(func) #此时的func不再是原来的func,而变成了inner函数
result = func()
print(result)

2.2、第二次比较

正常实现方式不变,我们改写闭包实现方式。

Python的语法糖中存在特殊的语法,在某个函数的上方使用:

@函数名 def xxx(): pass python内部会自动执行,函数名(xxx),执行完后,再将结果赋值给xxx。 xxx = 函数名(xxx)

改进闭包实现

def outer(origin):
	def inner():
		print('before') #加上执行前的before
		res = origin() #调用原来的func函数
		print('after') #加上执行后的after
		return res
	return inner
@outer #func=outer(func)
def func():
	print("我是func函数")
	va1ue(11,22,33,44)
	return value

result = func()
print(result)

2.3、第三次比较

当我存在多个函数时,在不修改源码的情况下。实现在函数执行前和执行后分别输入"before"和"after"。

def func1():
	print("我是func1函数")
	va1ue(11,22,33,44)
	return value

result func1()
print(result)

def func2():
	print("我是func2函数")
	va1ue(11,22,33,44)
	return value

result func2()
print(result)

def func3():
	print("我是func3函数")
	va1ue(11,22,33,44)
	return value

result func3()
print(result)

正常实现方式需要对每个函数内部进行修改 闭包实现如下:

def outer(origin):
	def inner():
		print('before') #加上执行前的before
		res = origin() #调用原来的func函数
		print('after') #加上执行后的after	
		return res
	return inner

@outer
def func1():
	print("我是func1函数")
	va1ue(11,22,33,44)
	return value

@outer
def func2():
	print("我是func2函数")
	va1ue(11,22,33,44)
	return value

@outer
def func3():
	print("我是func3函数")
	va1ue(11,22,33,44)
	return value

func1()
func2()
func3()

因此,我们这里对应用场景做一个简单的总结:如果对与修改的函数比较少,只是需要对函数的前后增加一部分功能,可以直接修改原函数;如果我们需要修改的原函数比较多,我们可以通过装饰器(对函数进行装饰,不改变内部结构)的方式进行增加函数功能。

2.4、装饰器优化支持多个参数

如果原来的函数含有多个参数

#对于需要装饰的函数含有参数的问题,需要在inner和origin函数后面跟上不定长的参数选项
def outer(origin):
	def inner(*args,**kwargs):
		print('before') #加上执行前的before
		res = origin(*args,**kwargs) #调用原来的func函数
		print('after') #加上执行后的after
		return res
	return inner

@outer
def func1(a1):
	print("我是func1函数")
	va1ue(11,22,33,44)
	return value

@outer
def func2(a1,a2):
	print("我是func2函数")
	va1ue(11,22,33,44)
	return value

@outer
def func3(a1):
	print("我是func3函数")
	va1ue(11,22,33,44)
	return value

func1()
func2()
func3()

3、更深层次的伪造

def outer(func):
	def inner(*args,**kwargs):
		'''这是inner函数的注释'''
		res = func(*args,**kwargs) #调用原来的func函数
		return res	
	return inner

 @outer
def func():
	'''这是func函数的注释'''
	pass
func()

#在未用装饰器之前
#print(func.__name__) #'func'
#print(func.__doc__) #这是func函数的注释

#在用装饰器之后
print(func.__name__) #'inner'
print(func.__doc__) #这是inner函数的注释

很显然装饰器会改变原来函数,但有些时候我们不需要改变原来函数的注释和名称,我们可以使用python内置的functools模块,具体代码看一看装饰器总结

4、装饰器总结

  • 实现原理:基于@语法和函数闭包,将原函数封装在闭包中,然后将函数赋值为一个新的函数(内层函数),执行函数时再在内层函数中执行闭包中的原函数。
  • 实现效果:可以在不改变原函数内部代码和调用方式的前提下,实现在函数执行和执行扩展功能。
  • 适用场景:多个函数系统统一在执行前后自定义一些功能。
  • 模板代码:
import functools
def outer(func):
	@functools.wraps(func) #inner.__name__ = func.__name__    inner.__doc__=func.__doc__
	def inner(*args,**kwargs):
		# 执行前
		res = func(*args,**kwargs) #调用原来的func函数
		# 执行后
		return res	
	return inner
 @outer
def func():
	pass
func()
鲸之声为您拼命加载中...