gpt4 book ai didi

Python "Multi-Level Decorator"- 这是如何工作的?

转载 作者:太空宇宙 更新时间:2023-11-04 00:59:53 24 4
gpt4 key购买 nike

我一直在脚本中编写一些数据库操作函数,并决定使用函数装饰器来处理数据库连接样板。

下面显示了一个简化的示例。

函数装饰器:

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 对象似乎不再被初始化或调用。

问题:

  1. 这项技术有名字吗?
  2. 谁能进一步说明内部发生的事情?

最佳答案

您已经创建了一个装饰器工厂;生成装饰器的可调用对象。在这种情况下,您忽略 globaldec.__init__()func 参数(原始funcdec 类对象)当使用 globaldec 类作为装饰器时。您将其替换为 globaldec 类的实例,然后将其用作 function1function2 的真正装饰器。

那是因为装饰器只是语法糖;应用于 class funcdec: 行的 @globaldec 装饰器可以这样表示:

class funcdec(object):
pass
funcdec = globaldec(funcdec)

因此 funcdec 类被替换为 globaldec 的实例。

我不使用类,而是使用函数; funcstate 等状态成为闭包。

你原来的装饰器可以这样写:

import random

def funcdec(func):
state = random.random()
def wrapper(*args, **kwargs):
return func(state, *args, **kwargs)
return wrapper

因此,当 Python 将其用作装饰器时,funcdec() 返回 wrapper 函数,替换原来的 function1function2 函数被该函数对象替换。调用 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 作为共享值。

关于Python "Multi-Level Decorator"- 这是如何工作的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33329652/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com