创建闭包的Pythonic方法

创建闭包的Pythonic方法,python,python-2.7,closures,metaprogramming,decorator,Python,Python 2.7,Closures,Metaprogramming,Decorator,我的代码存在于GUI之外的文件中,但生成GUI调用的方法。例如,此文件包含如下函数: # old code def fixDictionary(dictionary, key, new_value): def fix(): dictionary[key] = new_value return fix # old code def checkDictionary(dictionary): errors = [] for key, value in

我的代码存在于GUI之外的文件中,但生成GUI调用的方法。例如,此文件包含如下函数:

# old code
def fixDictionary(dictionary, key, new_value):
    def fix():
        dictionary[key] = new_value
    return fix
# old code
def checkDictionary(dictionary):
    errors = []
    for key, value in dictionary.items():
        if value == 'old_value':
            error.append(fixDictionary(dictionary, key, 'new_value'))
    return errors
在闭包中包装
字典
的一般方法效果很好,但这种方法会导致大量用于创建无参数函数的样板代码。我制作了一个简单的装饰器,可以为我完成这项工作,如下所示

# new code
from functools import wraps

def strip_args(function):
    def outer(*args, **kwargs):

        @wraps(function)
        def inner():
            function(*args, **kwargs)
        return inner

    return outer

@strip_args
def fixDictionary(dictionary, key, new_value):
    dictionary[key] = new_value
作为参考,此函数的用法如下所示:

dictionary = {'key': 'old_value'}

fixer = fixDictionary(dictionary, 'key', 'new_value')
fixer()

print(dictionary) # {'key': 'new_value'}
dictionary = {'key': 'old_value'}
errors = checkDictionary(dictionary) # [<function fixDictionary at 0x01806C30>]
errors[0]()
print(dictionary) # {'key': 'new_value'}
然后,我的代码中还有一组方法,它们看起来像:

# old code
def fixDictionary(dictionary, key, new_value):
    def fix():
        dictionary[key] = new_value
    return fix
# old code
def checkDictionary(dictionary):
    errors = []
    for key, value in dictionary.items():
        if value == 'old_value':
            error.append(fixDictionary(dictionary, key, 'new_value'))
    return errors
如果不清楚,这些方法将检查对象是否存在错误,然后返回GUI可以调用的匿名函数以更正这些错误。但是,所有这些方法都会初始化空白容器,向其中添加项,然后返回它。为了删除所有这些函数中的重复代码,我编写了另一个decorator:

# new code
def init_and_return(**init_dict):
    if len(init_dict) != 1:
        raise ValueError('Exactly one "name=type" pair should be supplied')

    _name, _type = init_dict.items()[0]

    def outer(function):

        @wraps(function)
        def inner(*args, **kwargs):
            _value = _type()
            function.func_globals[_name] = _value
            function(*args, **kwargs)
            return _value
        return inner

    return outer

@init_and_return(errors=list)
def checkDictionary(dictionary):
    for key, value in dictionary.items():
        if value == 'old_value':
            errors.append(fixDictionary(dictionary, key, 'new_value'))
现在,最终的用法如下所示:

dictionary = {'key': 'old_value'}

fixer = fixDictionary(dictionary, 'key', 'new_value')
fixer()

print(dictionary) # {'key': 'new_value'}
dictionary = {'key': 'old_value'}
errors = checkDictionary(dictionary) # [<function fixDictionary at 0x01806C30>]
errors[0]()
print(dictionary) # {'key': 'new_value'}
dictionary={'key':'old_value'}
错误=检查字典(字典)#[]
错误[0]()
打印(字典)#{'key':'new_value'}
这也非常有效,并允许我避免为这些函数编写更多的样板文件。关于上述实施,我有两个问题:

  • 是否有一种更具python风格的方法来实现此功能?其目的是消除每个函数中的所有样板代码,但编写函数
    strip_args
    init_和_return
    肯定会使大脑紧张。虽然像这样的函数不需要经常编写,但它们似乎与实际行为相去甚远
  • function.func\u globals[\u name]=\u value
    具有不希望的行为;它允许从全局范围访问
    错误
    。这并不是世界末日,因为每次调用函数时都会重置变量,但我是否需要设置局部变量?我已经尝试将这一行更改为
    locals()[\u name]=\u value
    ,但该作用域没有执行到函数中。这一级别的元编程是否超出了Python的预期范围

  • 我找到了解决第二个问题的方法,将一些簿记代码实现到
    init_和_return
    函数中,该函数检查它是否覆盖了全局变量,如果是,则恢复它(如果不是,则删除它)