0
点赞
收藏
分享

微信扫一扫

Python装饰器详细解析

A邱凌 2022-03-11 阅读 54

1.在理解python解释器前先了解以下知识点:
闭包是什么?
函数中定义函数,且外层函数的返回值是内层函数,例如:

def outer(a):
	def inner(b):
		return a+b
	return inner
print(outer(5)(6))  # 输出的结果是11
# 说明:python中函数本身就是对象,所以outer(5)实际引用的和inner同一个内存地址也就是同一个对象,
# outer(5)(6)实际就是在调用inner这个函数对象

*args和**kwargs的作用
是函数可以接收数量不确定的参数,*args在参数中以元组形式接收, **kwargs以字典key-value的形式接收

def aaa(a,b):
	print(a+b)

def bbb(*args, **kwargs):
	aaa(*args, **kwargs)
bbb(1,2) # 不会报错
bbb(1,2,3) # 会报错,原因是在bbb函数中调用aaa函数时值参数不对,aaa函数只能接收2个参数,
# bbb函数会以元组的形式接受(1,2,3),当调用aaa时*args会解析(1,2,3)为3个参数传递给aaa,
# 所以参数数量不匹配报错

2.无参函数装饰器
给一个函数添加附带功能

def decorator(func)
	def wrapper(*args, *kwargs):
		print("start")
		func(*args, **kwargs)
		print(end)

@decorator
def add(a,b):
	print(a+b)

add(1,2)  
# 这里的add是 def add这个对象吗? 不是,这里add实际是wrapper函数指向的对象。@会被python解释器
# 加载代码时自动执行,等价与 add = decorator(add), 所以add引用的是wrapper函数对象,wrapper对象里面的func引用的才是def add定义的函数对象
decorator(add)(1,2) # 想想这个函数执行会输出什么,关键是这里add指的是什么

3.有参函数装饰器
基于上面的分析,有参函数装饰器关键是理解@arg_decorator("Level1","Running")是怎么执行的

def arg_decorator(Level, Status):
	print("Level=%,Status=%s"%(Level,Status))
	def inner_deco(func):
		def wrapper(*args, **kwargs):
			print("Level=%,Status=%s"%(Level,Status))
			print("start")
			func(*args, **kwargs)
			print("end")
		return wrapper
	return inner_deco
	
@arg_decorator("Level1", "Running")
def add(a,b):
	print(a+b)

add(1,2) # 如果将add(1,2)这行注释掉直接执行,会有输出吗?
# 说明程序在python解释器加载代码时,自动执行 arg_decorator("Level1","Running"),
# 会返回inner_deco这个函数对象,所以就等价于@inner_deco, 成了一个无参函数装饰器了

4.元信息的保存
元信息指一个函数和类对象名称__name__,文档注解__doc__等等,其他内置属性参考:
pyhton内置的函数属性

from functools import wraps
def arg_decorator(Level, Status):
	print("Level=%,Status=%s"%(Level,Status))
	def inner_deco(func):
		@wraps(func)
		def wrapper(*args, **kwargs):
			print("Level=%,Status=%s"%(Level,Status))
			print("start")
			func(*args, **kwargs)
			print("end")
		return wrapper
	return inner_deco **
	
@arg_decorator("Level1", "Running")
def add(a,b):
	print(a+b)
print(add.__doc__)
print(add.__name__)

5.无参数类装饰器
将装饰器定义成一个类,你必须确保这个类实现了__call__()__init__方法。

from functools import wraps
class ClsDecorator():
	def __init__(self, func):
		print("__init__ called")
		wraps(func)(self)  # 此句会修改类的元信息为func的元信息
		self.f = func
	def __call__(self, *args, **kwargs):
		print("__call__ called")
		print("start")
		print(self.f(*args, **kwargs))
		print("end")

@ClsDecorator
def add(a, b):
	return a + b
add(1,2) # 这里的add实际上ClsDecorator的实例对象
# 说明:执行的过程是:@ClsDecorator执行的过程是 
# 1.add = ClsDecorator(add)生成实例对象,(在python解释器加载代码时自动执行)
# 2.add(1,2)实际上调用的是__call__函数

6.有参数的类装饰器
和有参数的函数装饰器一样,主要是理解@ClsDecorator(1,2)的执行过程

from functools import wraps
class ClsDecorator():
	def __init(self, a, b):
		print(a,b)
	def __call__(self, func):
		print("__call__ called")
		@wraps(func) # 获取元信息
		def wrapper(*args, **kwargs):
			print("start")
			func(*args, **kwargs)
			print("end")

@ClsDecorator(1, 2)
def add(a, b):
	print(a + b)
举报

相关推荐

0 条评论