Python 2.7:根据全局变量定义默认参数?

时间:2014-02-21 15:28:37

标签: python-2.7 global default-parameters

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

说我有一个文件Script_Defaults.py with

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_INPUT设置为FalseTrue。为了得到这种行为,我现在正在使用它......

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,以及许多需要它们的函数。是否有更好的功能,或者这是唯一的方法吗?

1 个答案:

答案 0 :(得分: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装饰器从默认值dict中取出哪个值。

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

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