我正在写一个(python3
)程序,当我试图实现一个(函数)装饰器来更新一个外部变量(一种发出信号的装饰器)时,我被卡住了。问题在于不同功能范围之间的冲突。我已经环顾了一些类似的问题,但我还没有找到有用的一个。。。如果可能的话,我需要尊重一些设计限制(见下文),我也希望避免使用外部库
这里是一个使用global
关键字的工作示例,它可以用作起点
VAR = 'i am a global variable'
# decorator
def update_external_variable():
def f_wrapper(f):
def p_wrapper(p, q):
r = f(p, q) + ': updating the global variable ??'
global VAR
VAR = r
return r
return p_wrapper
return f_wrapper
@update_external_variable()
def a(p, q): return 'a({}, {})'.format(p, q) #target function
o = a('v', 'w')
print(VAR, id(VAR))
输出
a(v, w): updating the global variable ?? 140497617759280 # yes, it works!
设计限制1:修饰符update_external_variable
不应依赖于外部变量标识符(名称),因此必须将其作为参数传递。update_external_variable
的签名应该包含全局变量VAR
的信息
尝试1:mokey补丁方式-我尝试模拟上面的工作示例,但没有结果
VAR = 'i am a global variable'
# decorator
def update_external_variable(ext_var_id): # ext_var_id: string with the variable identifier
def f_wrapper(f):
def p_wrapper(p, q):
r = f(p, q) + ': updating the global variable ??'
exec('global {}'.format(ext_var_id), {}) # -> global VAR
exec('{} = "{}"'.format(ext_var_id, eval(ext_var_id))) # initialize VAR??
#print(dir())
return r
return p_wrapper
return f_wrapper
@update_external_variable(ext_var_id='VAR')
def a(p, q): return 'a({}, {})'.format(p, q) #target function
o = a('v', 'w')
print(o, id(o))
输出
a(v, w): updating the global variable ?? 140686557781040
i am a global variable # failure!
尝试2:参数的方式
VAR = 'i am a global variable'
# decorator
def update_external_variable(ext_var): # ext_var: reference of the global variable
def f_wrapper(f):
def p_wrapper(p, q, ext_var=ext_var):
r = f(p, q) + ': updating the global variable ??'
# global ext_var <- will raise to an error since point to the parameter..
print(ext_var)
ext_var = r
return r
return p_wrapper
return f_wrapper
@update_external_variable(ext_var=VAR)
def a(p, q): return 'a({}, {})'.format(p, q) # target function
o = a('v', 'w')
print(o, id(o))
print(VAR)
输出
i am a global variable
a(v, w): updating the global variable ?? 140406972742896
i am a global variable # failure!
设计限制2:如果存在使用尝试2的解决方案,那么我需要对p_wrapper
的签名施加以下限制,这可能会导致进一步的问题:def p_wrapper(*args, **kwargs): ...
要给装饰者一个通用指纹,我需要p_wrapper
的参数要成为要修饰的函数,r = func(*args, **kwargs)
如果有人对如何解决这个问题有想法,可以是尝试1或尝试2,甚至是它们的组合,也可以是其他解决方案,我将非常感激
提前感谢:)
不要使用单个全局变量;使用修饰函数可以更新的
dict
如果出于任何原因,您的装饰程序必须使用无法更改的现有全局变量,请使用
globals()
访问必要的dict
相关问题 更多 >
编程相关推荐