我正在编写一个实用程序,我希望有一个全局变量来改变函数的运行方式。默认情况下,我希望所有函数都遵循一种风格,但在某些情况下,我也希望强制函数运行的方式。
说我有一个文件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
设置为False
或True
。为了得到这种行为,我现在正在使用它......
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
,以及许多需要它们的函数。是否有更好的功能,或者这是唯一的方法吗?
答案 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):
...