装饰器和变量作用域
Decorators and variables scope
我正在编写一个 (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
。
VARS = {
'var1': ...,
'var2': ...,
}
# decorator
def update_external_variable(varkey):
def f_wrapper(f):
def p_wrapper(p, q):
r = f(p, q) + ': updating the global variable ??'
VARS[varkey] = r
return r
return p_wrapper
return f_wrapper
@update_external_variable('var1')
def a(p, q):
return 'a({}, {})'.format(p, q) #target function
o = a('v', 'w')
print(VARS['var1'])
如果出于某种原因,您的装饰器必须使用您无法更改的现有全局变量,请使用 globals()
访问必要的 dict
。
VAR1 = ...
VAR2 = ...
# decorator
def update_external_variable(varkey):
def f_wrapper(f):
def p_wrapper(p, q):
r = f(p, q) + ': updating the global variable ??'
globals()[varkey] = r
return r
return p_wrapper
return f_wrapper
# Still passing the *name* of the variable as a string
@update_external_variable('VAR1')
def a(p, q):
return 'a({}, {})'.format(p, q) #target function
o = a('v', 'w')
print(VAR1)
我正在编写一个 (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
。
VARS = {
'var1': ...,
'var2': ...,
}
# decorator
def update_external_variable(varkey):
def f_wrapper(f):
def p_wrapper(p, q):
r = f(p, q) + ': updating the global variable ??'
VARS[varkey] = r
return r
return p_wrapper
return f_wrapper
@update_external_variable('var1')
def a(p, q):
return 'a({}, {})'.format(p, q) #target function
o = a('v', 'w')
print(VARS['var1'])
如果出于某种原因,您的装饰器必须使用您无法更改的现有全局变量,请使用 globals()
访问必要的 dict
。
VAR1 = ...
VAR2 = ...
# decorator
def update_external_variable(varkey):
def f_wrapper(f):
def p_wrapper(p, q):
r = f(p, q) + ': updating the global variable ??'
globals()[varkey] = r
return r
return p_wrapper
return f_wrapper
# Still passing the *name* of the variable as a string
@update_external_variable('VAR1')
def a(p, q):
return 'a({}, {})'.format(p, q) #target function
o = a('v', 'w')
print(VAR1)