Python迷惑之反向装饰器(将被装饰函数传入装饰器的函数参数内调用)

正常装饰器

看一个正常的装饰器:

	def deco(*arg):
	    print(1, arg)
	    def inner(func):
	        print(2, func)
	        print('inner')
	
	        return func
	        
	    return inner

然后我们装饰一个函数:

	@deco('arg')
	def main():
	    return

打印结果如下:

	1 ('arg',)
	2 <function main at 0x0000017174880310>
	inner

一点毛病没有,1 的打印位置就是事先处理区域,先执行了,再将 main() 当做 func 传入,执行 inner() 内的内容。

反向装饰器

试想我们将函数传入:

	def deco(*arg):
	    print(1, arg)
	    def inner(func):
	        print(2, func)
	        print('inner')
	        return func
	        
	    return inner
	
	def test():
	    return
	
	@deco(test)
	def main():
	    return

这段和正常装饰器无异,那么 arg 就应该是传入的 test() 函数,打印如下:

	1 (<function test at 0x000001CC83B90160>,)
	2 <function main at 0x000001CC83B90310>
	inner

之后我们试想给 return 的 inner 传入参数,他会把 main() 也就是被装饰的函数传入装饰器参数的函数中:

	def deco(*arg):
	    print(1, arg)
	    def inner(func):
	        print(2, func)
	        print('inner')
	        return func
	        
	    return inner(arg[0])
	
	def test(fun):
	    print('test:', fun)
	    return
	
	@deco(test)
	def main():
	    return

这里给 inner() 只传了 arg[0] 一个,也就是我们传入的 test() 函数,打印如下:

	1 (<function test at 0x000001C5BEED00D0>,)
	2 <function test at 0x000001C5BEED00D0>
	inner
	test: <function main at 0x000001C5BEED0160>

可以发现 inner(func) 的参数因为我们传入 test() 函数污染了,不再是 main() 函数了,main() 函数跑到了 test() 函数的参数里。

从而我们就实现了,被装饰函数传入装饰器参数中的函数内调用!

这里传入的 test() 不可以换为其他的变量,他必须是可 callable 的,另外, 能给 return inner 传参,不也能给 return func 传参吗,给 func 传参就是给 main() 传参,这个一目了然,不是迷惑行为。

	def deco(*arg):
	    print(1, arg)
	    def inner(func):
	        print(2, func)
	        print('inner')
	        return func(arg[0])
	        
	    return inner
	
	def test(fun):
	    print('test:', fun)
	    return
	
	@deco(test)
	def main(param):
	    print('main: ', param)
	    return

打印结果:

	1 (<function test at 0x0000019F19CE00D0>,)
	2 <function main at 0x0000019F19CE01F0>
	inner
	main:  <function test at 0x0000019F19CE00D0>

给 func 传参的话,没什么不可理解的,把装饰器上的参数给被装饰的函数调用而已,而且还执行了 main() 函数。

总结

不在 inner() 内主动调用 main() (被装饰函数)为前提。

那么,正向装饰中,我们可以把 test() 传给 return func() 中作为参数,从而把装饰器参数中的函数传给了被装饰函数作为参数 + 调用被装饰函数。

在反向装饰中,我们用 test() 污染了 inner() ,从而实现了将被装饰函数传给装饰器参数中的函数作为参数 + 调用装饰器参数中的函数。

你可能感兴趣的:(Python,python,生成器,deco,装饰器)