Python装饰器不识别全局变量
Python decorator does not recognize global variable
我刚刚编码的问题的mwe:
from decorator import decorator
@decorator
def deco(func, deco_name=None, *args, **kwargs):
print(f"DECORATOR {deco_name} APPLIED")
return func(*args, **kwargs)
deco_name = None
class Greeter:
def __init__(self, _deco_name):
global deco_name
deco_name = _deco_name
@deco(deco_name=deco_name)
def hello(self, name):
print(f"Hello {name} :)")
print(deco_name)
g = Greeter("MYDECO")
g.hello("Yoshi")
控制台输出:
DECORATOR None APPLIED
Hello Yoshi :)
MYDECO
我在我的项目中有一个类似的设置,我不明白为什么装饰函数 deco() 不知道全局变量 deco_name 的更新值的值(它打印 DECORATOR None APPLIED 而不是 DECORATOR MYDECO APPLIED)。
装饰函数 hello() 确实知道更新值,如 MYDECO 所见,由最后一个打印语句生成。
我需要一些方法来在运行时设置一个全局变量并将其传递给装饰器,如果有人可以 a) 向我解释为什么我的方法是错误的并且 b) 给我一个 fix/alternative 解决方案,我会很高兴。
提前致谢。
我很确定这里发生的是 deco_name 在对象初始化之前被解释。当你在 class 中注释一个函数时,几乎发生的事情是,一旦 class 本身被解释,装饰器就“准备好了”,这意味着 @deco 在你分配 g.
最好的选择可能是将 hello 打包在一个不同的函数中,以实现装饰器的功能:
def hello(self, name):
return deco(self._hello, deco_name=self.deco_name, name)
def _hello(self, name):
# your hello
这也将全局 deco_name 替换为 class 属性。
主要问题是装饰器是在创建 class 时创建的。所以在设置变量之前会调用外部装饰器。您可以将所有这些放在包装函数中,这样它只会在调用 hello()
时被调用。
我不确定你为什么在这里使用全局变量。您可以在包装函数中访问实例变量,这对我来说更有意义。下面是一个设置和访问全局变量和实例变量的示例。也许它将指向一个有用的方向:
def deco(f):
def wrapper(*args):
instance = args[0]
print(f"DECORATOR Instance {instance.deco_name} APPLIED")
print(f"GLOBAL NAME {global_deco_name} APPLIED")
f(*args)
return wrapper
global_deco_name = "global_deco"
class Greeter:
def __init__(self, _deco_name):
global global_deco_name
self.deco_name = _deco_name
global_deco_name = _deco_name
@deco
def hello(self, name):
print(f"Hello {name} :)")
print(self.deco_name)
print(global_deco_name)
g = Greeter("MYDECO")
g.hello("Yoshi")
版画
DECORATOR Instance MYDECO APPLIED
GLOBAL NAME MYDECO APPLIED
Hello Yoshi :)
MYDECO
MYDECO
我刚刚编码的问题的mwe:
from decorator import decorator
@decorator
def deco(func, deco_name=None, *args, **kwargs):
print(f"DECORATOR {deco_name} APPLIED")
return func(*args, **kwargs)
deco_name = None
class Greeter:
def __init__(self, _deco_name):
global deco_name
deco_name = _deco_name
@deco(deco_name=deco_name)
def hello(self, name):
print(f"Hello {name} :)")
print(deco_name)
g = Greeter("MYDECO")
g.hello("Yoshi")
控制台输出:
DECORATOR None APPLIED
Hello Yoshi :)
MYDECO
我在我的项目中有一个类似的设置,我不明白为什么装饰函数 deco() 不知道全局变量 deco_name 的更新值的值(它打印 DECORATOR None APPLIED 而不是 DECORATOR MYDECO APPLIED)。 装饰函数 hello() 确实知道更新值,如 MYDECO 所见,由最后一个打印语句生成。 我需要一些方法来在运行时设置一个全局变量并将其传递给装饰器,如果有人可以 a) 向我解释为什么我的方法是错误的并且 b) 给我一个 fix/alternative 解决方案,我会很高兴。
提前致谢。
我很确定这里发生的是 deco_name 在对象初始化之前被解释。当你在 class 中注释一个函数时,几乎发生的事情是,一旦 class 本身被解释,装饰器就“准备好了”,这意味着 @deco 在你分配 g.
最好的选择可能是将 hello 打包在一个不同的函数中,以实现装饰器的功能:
def hello(self, name):
return deco(self._hello, deco_name=self.deco_name, name)
def _hello(self, name):
# your hello
这也将全局 deco_name 替换为 class 属性。
主要问题是装饰器是在创建 class 时创建的。所以在设置变量之前会调用外部装饰器。您可以将所有这些放在包装函数中,这样它只会在调用 hello()
时被调用。
我不确定你为什么在这里使用全局变量。您可以在包装函数中访问实例变量,这对我来说更有意义。下面是一个设置和访问全局变量和实例变量的示例。也许它将指向一个有用的方向:
def deco(f):
def wrapper(*args):
instance = args[0]
print(f"DECORATOR Instance {instance.deco_name} APPLIED")
print(f"GLOBAL NAME {global_deco_name} APPLIED")
f(*args)
return wrapper
global_deco_name = "global_deco"
class Greeter:
def __init__(self, _deco_name):
global global_deco_name
self.deco_name = _deco_name
global_deco_name = _deco_name
@deco
def hello(self, name):
print(f"Hello {name} :)")
print(self.deco_name)
print(global_deco_name)
g = Greeter("MYDECO")
g.hello("Yoshi")
版画
DECORATOR Instance MYDECO APPLIED
GLOBAL NAME MYDECO APPLIED
Hello Yoshi :)
MYDECO
MYDECO