0

我正在编写一个实用程序,我希望在其中拥有改变函数运行方式的全局变量。默认情况下,我希望所有函数都遵循一种风格,但在某些情况下,我还希望能够强制函数操作的方式。

假设我有一个文件 Script_Defaults.py

USER_INPUT = True

在另一个 python 文件中,我有很多这样的函数:

from Script_Defaults import USER_INPUT
def DoSomething(var_of_data, user_input = USER_INPUT):
    if user_input:
        ... #some code here that asks the user what to change in var_of_data
    .... # goes on to do something

我在这里面临的问题是默认参数仅在文件启动时加载一次。我希望能够设置USER_INPUTFalseTrue在程序运行期间。为了获得这种行为,我目前正在像这样使用它......

from Script_Defaults import USER_INPUT
def DoSomething(var_of_data, user_input = None):
    if user_input is None:
         user_input = USER_INPUT
    if user_input:
        ... #some code here that asks the user what to change in var_of_data
    .... # goes on to do something

这似乎是很多不必要的代码,特别是如果我有很多条件,比如USER_INPUT,以及许多需要它们的函数。有没有更好的方法来获得这个功能,或者这是唯一的方法?

4

1 回答 1

2

使用装饰器和处理函数的默认参数,您可以使用以下解决方案:

from change_defaults import Default, set_defaults

my_defaults = dict(USER_INPUT=0)


@set_defaults(my_defaults)
def DoSomething(var_of_data, user_input=Default("USER_INPUT")):
    return var_of_data, user_input


def main():
    print DoSomething("This")

    my_defaults["USER_INPUT"] = 1

    print DoSomething("Thing")

    my_defaults["USER_INPUT"] = 2

    print DoSomething("Actually")
    print DoSomething("Works", 3)


if __name__ == "__main__":
    main()

这需要以下代码:

# change_defaults.py

from functools import wraps

class Default(object):
    def __init__(self, name):
        super(Default, self).__init__()

        self.name = name


def set_defaults(defaults):
    def decorator(f):
        @wraps(f)
        def wrapper(*args, **kwargs):
            # Backup original function defaults.
            original_defaults = f.func_defaults

            # Replace every `Default("...")` argument with its current value.
            function_defaults = []
            for default_value in f.func_defaults:
                if isinstance(default_value, Default):
                    function_defaults.append(defaults[default_value.name])
                else:
                    function_defaults.append(default_value)

            # Set the new function defaults.
            f.func_defaults = tuple(function_defaults)

            return_value = f(*args, **kwargs)

            # Restore original defaults (required to keep this trick working.)
            f.func_defaults = original_defaults

            return return_value

        return wrapper

    return decorator

通过定义默认参数,Default(parameter_name)告诉set_defaults装饰器从默认字典中获取哪个值。

此外,使用更多代码(与解决方案无关),您可以使其工作如下:

@set_defaults(my_defaults)
def DoSomething(var_of_data, user_input=Default.USER_INPUT):
    ...
于 2014-02-21T16:47:32.907 回答