Python "Multi-Level Decorator" - 这是如何工作的?
Python "Multi-Level Decorator" - how does this work?
我一直在脚本中编写一些数据库操作函数,并决定使用函数装饰器来处理数据库连接样板文件。
下面显示了一个简化的示例。
函数装饰器:
import random
class funcdec(object):
def __init__(self,func):
self.state = random.random()
self.func = func
def __call__(self,*args,**kwargs):
return self.func(self.state,*args,**kwargs)
@funcdec
def function1(state,arg1,**kwargs):
print(state)
@funcdec
def function2(state,arg2,**kwargs):
print(state)
function1(10)
function2(20)
这意味着我可以减少样板文件的数量,但每个函数都有不同的状态对象。所以如果我 运行 这个我得到类似的东西:
python decf.py
0.0513280070328
0.372581711374
我想实现一种让所有装饰函数共享此状态的方法,我想到了这个。
装饰函数装饰器:
import random
class globaldec(object):
def __init__(self,func):
self.state = random.random()
def __call__(self,func,*args,**kwargs):
def wrapped(*args,**kawrgs):
return func(self.state,*args,**kwargs)
return wrapped
@globaldec
class funcdec(object):
pass
@funcdec
def function1(state,arg1,**kwargs):
print(state)
@funcdec
def function2(state,arg2,**kwargs):
print(state)
function1(10)
function2(20)
现在,当我 运行 这个状态对象只为每个应用程序创建一次并且状态对于所有装饰函数都是相同的,例如:
python decg.py
0.489779827086
0.489779827086
直觉上这对我来说很有意义,因为 globaldec
只为函数装饰器的所有实例初始化一次。
但是,我对这里到底发生了什么有点模糊,而且 funcdec
对象似乎不再被初始化或调用。
问题:
- 这个技术有名字吗?
- 任何人都可以进一步说明内部发生的事情吗?
您已经创建了一个装饰器工厂;生成装饰器的可调用对象。在这种情况下,当使用 globaldec
class 作为装饰器。您将其替换为 globaldec
class 的实例,然后将其用作 function1
和 function2
.
的真正装饰器
那是因为装饰器只是语法糖;应用于 class funcdec:
行的 @globaldec
装饰器可以这样表达:
class funcdec(object):
pass
funcdec = globaldec(funcdec)
所以 funcdec
class 被 globaldec
的实例代替。
我不使用 classes,而是使用函数; func
和 state
等状态变为闭包。
你原来的装饰器可以这样写:
import random
def funcdec(func):
state = random.random()
def wrapper(*args, **kwargs):
return func(state, *args, **kwargs)
return wrapper
所以当Python将其作为装饰器应用时,funcdec()
returns wrapper
函数,替换原来的 function1
或 function2
函数被该函数对象替换。调用 wrapper()
然后通过 func
闭包依次调用原始函数对象。
globaldec
版本只是增加了一层;外部函数生成装饰器,将闭包移出一步:
import random
def globaldec():
state = random.random()
def funcdec(func):
def wrapper(*args, **kwargs):
return func(state, *args, **kwargs)
return wrapper
return funcdec
只需创建一次装饰器:
funcdec = globaldec()
@funcdec
def function1(state,arg1,**kwargs):
print(state)
@funcdec
def function2(state,arg2,**kwargs):
print(state)
另一种模式是将状态存储为全局状态(您可以直接在装饰器函数上这样做:
import random
def funcdec(func):
if not hasattr(funcdec, 'state'):
# an attribute on a global function is also 'global':
funcdec.state = random.random()
def wrapper(*args, **kwargs):
return func(funcdec.state, *args, **kwargs)
return wrapper
现在您不再需要生成专用装饰器对象,wrapper
现在引用 funcdec.state
作为共享值。
我一直在脚本中编写一些数据库操作函数,并决定使用函数装饰器来处理数据库连接样板文件。
下面显示了一个简化的示例。
函数装饰器:
import random
class funcdec(object):
def __init__(self,func):
self.state = random.random()
self.func = func
def __call__(self,*args,**kwargs):
return self.func(self.state,*args,**kwargs)
@funcdec
def function1(state,arg1,**kwargs):
print(state)
@funcdec
def function2(state,arg2,**kwargs):
print(state)
function1(10)
function2(20)
这意味着我可以减少样板文件的数量,但每个函数都有不同的状态对象。所以如果我 运行 这个我得到类似的东西:
python decf.py
0.0513280070328
0.372581711374
我想实现一种让所有装饰函数共享此状态的方法,我想到了这个。
装饰函数装饰器:
import random
class globaldec(object):
def __init__(self,func):
self.state = random.random()
def __call__(self,func,*args,**kwargs):
def wrapped(*args,**kawrgs):
return func(self.state,*args,**kwargs)
return wrapped
@globaldec
class funcdec(object):
pass
@funcdec
def function1(state,arg1,**kwargs):
print(state)
@funcdec
def function2(state,arg2,**kwargs):
print(state)
function1(10)
function2(20)
现在,当我 运行 这个状态对象只为每个应用程序创建一次并且状态对于所有装饰函数都是相同的,例如:
python decg.py
0.489779827086
0.489779827086
直觉上这对我来说很有意义,因为 globaldec
只为函数装饰器的所有实例初始化一次。
但是,我对这里到底发生了什么有点模糊,而且 funcdec
对象似乎不再被初始化或调用。
问题:
- 这个技术有名字吗?
- 任何人都可以进一步说明内部发生的事情吗?
您已经创建了一个装饰器工厂;生成装饰器的可调用对象。在这种情况下,当使用 globaldec
class 作为装饰器。您将其替换为 globaldec
class 的实例,然后将其用作 function1
和 function2
.
那是因为装饰器只是语法糖;应用于 class funcdec:
行的 @globaldec
装饰器可以这样表达:
class funcdec(object):
pass
funcdec = globaldec(funcdec)
所以 funcdec
class 被 globaldec
的实例代替。
我不使用 classes,而是使用函数; func
和 state
等状态变为闭包。
你原来的装饰器可以这样写:
import random
def funcdec(func):
state = random.random()
def wrapper(*args, **kwargs):
return func(state, *args, **kwargs)
return wrapper
所以当Python将其作为装饰器应用时,funcdec()
returns wrapper
函数,替换原来的 function1
或 function2
函数被该函数对象替换。调用 wrapper()
然后通过 func
闭包依次调用原始函数对象。
globaldec
版本只是增加了一层;外部函数生成装饰器,将闭包移出一步:
import random
def globaldec():
state = random.random()
def funcdec(func):
def wrapper(*args, **kwargs):
return func(state, *args, **kwargs)
return wrapper
return funcdec
只需创建一次装饰器:
funcdec = globaldec()
@funcdec
def function1(state,arg1,**kwargs):
print(state)
@funcdec
def function2(state,arg2,**kwargs):
print(state)
另一种模式是将状态存储为全局状态(您可以直接在装饰器函数上这样做:
import random
def funcdec(func):
if not hasattr(funcdec, 'state'):
# an attribute on a global function is also 'global':
funcdec.state = random.random()
def wrapper(*args, **kwargs):
return func(funcdec.state, *args, **kwargs)
return wrapper
现在您不再需要生成专用装饰器对象,wrapper
现在引用 funcdec.state
作为共享值。