Python 参数化装饰器
Posted arthurlzyw
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python 参数化装饰器相关的知识,希望对你有一定的参考价值。
解析代码中的装饰器的时候,Python把被装饰的函数作为第一个参数传给装饰器函数。如果想让装饰器接受其他参数就需要创建一个装饰器工厂函数,再把参数传给它,返回一个装饰器,然后再把它应用到要装饰的函数上。
最简单的装饰器就如示例1中的register:
(示例1)
# BEGIN REGISTRATION_ABRIDGED registry = [] def register(func): print(‘running register(%s)‘ % func) registry.append(func) return func @register def f1(): print(‘running f1()‘) print(‘running main()‘) print(‘registry ->‘, registry) f1() # END REGISTRATION_ABRIDGED
为了便于启动和禁用register执行的函数注册功能,我们可以为它提供一个可选的active参数,设置为False时,不注册被装饰函数。实现方式如示例2:
(从概念上看,这个新的register函数不是装饰器,而是装饰器工厂函数。调用它会返回真正的装饰器,这个才是应用到目标函数上的装饰器)
(示例2)
# BEGIN REGISTRATION_PARAM registry = set() # <1> def register(active=True): # <2> def decorate(func): # <3> print(‘running register(active=%s)->decorate(%s)‘ % (active, func)) if active: # <4> registry.add(func) else: registry.discard(func) # <5> return func # <6> return decorate # <7> @register(active=False) # <8> def f1(): print(‘running f1()‘) @register() # <9> def f2(): print(‘running f2()‘) def f3(): print(‘running f3()‘) # END REGISTRATION_PARAM
< 1 > registry现在是一个set对象,这样添加和删除函数的速度更快。
< 2 > register接受一个可选的关键字参数。
< 3 > decorate这个内部函数是真正的装饰器,它的参数是一个函数。
< 4 > 只有active参数的值(从闭包中获取)是True时才注册func。
< 5 > 如果active不为真,而且func在register中,那么把它删除。
< 6 > decorate是一个装饰器,必须返回一个函数。
< 7 > register是装饰器工厂函数,因此返回decorate。
< 8 > @register工厂函数必须作为函数调用,并且传入所需参数。
< 9 > 即使不传入参数,register也必须作为函数调用(@register),就是要返回真正的装饰器decorate。
这里的关键是,register()要返回decorate,然后把它应用到被装饰的函数上。
示例2中的代码在registeration_param.py模块中。导入后得到结果如下:
>>>import registration_param running register(active=False)->decorate(<function f1 at 0x03320F18>) running register(active=True)->decorate(<function f2 at 0x03320ED0>)
>>>registration_param.registry
{<function f2 at 0x03320ED0>}
这里的f2函数在registry中;但是f1不在其中,因为传给register装饰器工厂函数的参数是active=False,所以应用到f1上的decorate没有把它添加到register中。
如果不使用@句法,那么就要像常规函数那样使用register;若想把f添加到register中,则装饰f函数的句法是register()( f );如果不想添加或者把它删除的话,句法是register(active=False)( f )。示例3演示如何把函数添加到register中,以及如何从中删除函数。
示例3
>>>from registration_param import* >>>registry #<1> {<function f2 at 0x03320ED0>} >>>register()(f3) #<2> running register(active=True)->decorate(<function f3 at 0x03320F60>) <function f3 at 0x03320F60> >>>registry #<3> {<function f2 at 0x03320ED0>, <function f3 at 0x03320F60>} >>>register(active=False)(f2) #<4> running register(active=False)->decorate(<function f2 at 0x03320ED0>) <function f2 at 0x03320ED0> >>>registry #<5> {<function f3 at 0x03320F60>}
< 1 > 导入这个模块的时候,f2在registry中。
< 2 > register()表达式返回decorate,然后把它应用到f3上。
< 3 > 前一行把f3添加到registry中。
< 4 > 这次调用从registry中删除f2。
< 5 > 确认registry。
参数化装饰器的原理非常复杂,参数化装饰器通常会把被装饰的函数替换掉,而且结构上需要多一层嵌套。
以上是关于Python 参数化装饰器的主要内容,如果未能解决你的问题,请参考以下文章
python笔记--3--函数生成器装饰器函数嵌套定义函数柯里化