系统学习Python——装饰器:函数装饰器-[对方法进行装饰:外层作用域引用]

分类目录:《系统学习Python》总目录


文章《系统学习Python——装饰器:函数装饰器-[对方法进行装饰:使用描述符装饰方法]》中我们介绍了使用描述符装饰方法,我们还可以使用一个嵌套的数和外层作用域引用来实现同样的效果一一下面的版本和前面的版本一样地有效,该版本通过为一个嵌套函数和作用域引用交换类和对象属性来实现。它所需的代码量显著减少,但是在被装饰的方法每次调用时都遵循同样的四步过程:

class tracer(object):
	def __init__(self, func):
		self.calls = 0
		self.func = func
	
	def __call__(self, *args, **kwargs):
		self.calls += 1
		print('call %s to %s' % (self.calls, self.func.__name__))
		return self.func(*args, **kwargs)
	
	def __get__(self, instance, owner):
		def wrapper(*args, **kwargs):
			return self(instance, *args, **kwargs)
		return wrapper

为这些替代方法添加print语句是为了自己跟踪获取/调用过程的多个步骤,用前面嵌套函数替代方案中同样的测试代码来运行它们。在两种编程方案中,基于描述符的方法比嵌套函数方法要细致得多,因此,它可能是这里的又一种选择,但其性能可能花费巨大。然而,在其他环境中这也可能是一种有用的编程模式。

值得注意的是,我们还可以像下面这样更简洁地编写这个基于描述符的装饰器,但是这之后它将只适用于方法,而不适用于简羊函数一一这是属性描述符的一个内在局限性(刚刚好是我们尝试要解决的问题的反面——在数和方法二者上同时应用):

class tracer(object):
	def __init__(self, func):
		self.calls = 0
		self.meth = meth
		
	def __get__(self, instance, owner):
		def wrapper(*args, **kwargs):
			self.calls += 1
			print('call %s to %s' % (self.calls, self.func.__name__))
			return self.meth (instance,*args, **kwargs)
		return wrapper

class Person:
	@tracer
	def giveRaise(self, percent):
		self.pay *= (1.0 + percent)

	@tracer
	def lastName(self):
		return self.name.split()[-1]

如果仅仅在函数上使用装饰器,我们将相当随意地使用类或函数来编写它们。一些装饰器可能并不需要最初类的实例,并且如果编写为类也能在函数和方法上同样有效,例如Python自己的staticmethod装饰器,就不需要主体类的一个实例(实际上,它主要是从调用中删除实例)。

然而,如果我们想要装饰器在简单函数和方法上都有效,则最好使用这里概述的基于嵌套函数的编程模式,而不是基于带有调用拦截的类。

参考文献:
[1] Mark Lutz. Python学习手册[M]. 机械工业出版社, 2018.

猜你喜欢

转载自blog.csdn.net/hy592070616/article/details/135349365