修饰符和变量作用域

2024-06-07 09:54:53 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在写一个(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,甚至是它们的组合,也可以是其他解决方案,我将非常感激

提前感谢:)


Tags: theidreturnvardefupdatewrapperam
1条回答
网友
1楼 · 发布于 2024-06-07 09:54:53

不要使用单个全局变量;使用修饰函数可以更新的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)

相关问题 更多 >

    热门问题