我试图找出如何覆盖某些模块中定义的函数的默认值。请考虑此代码(program.py
):
# import the default & user defined settings
from default_settings import *
from my_settings import *
# import some functions, which might be dependent on the settings above
from functions import *
# call dummy_function from 'functions' - prints '1'
dummy_function()
# output SOME_DEFAULT - will be '1'
print SOME_DEFAULT
# re-import 'my_settings' - SOME_DEFAULT will now be '2'
from my_settings import *
print SOME_DEFAULT
这里是default_settings.py
:
DO_DEBUG = False
SOME_DEFAULT = 1
这里是my_settings.py
,我想在functions.py
内使用哪些值:
DO_DEBUG = True
SOME_DEFAULT = 2
这是functions.py
,我需要导入default_settings
,否则我会得到一个NameError。我不想在此处导入my_settings
,因为functions.py
应该更像是通用库。
# if I leave this line out, then I get a
# "NameError: name 'SOME_DEFAULT' is not defined"
from default_settings import *
# I don't want to add "from my_settings import *" here, because 'functions.py'
# is supposed to be a generic library of functions.
# dummy decorator.
def do_profile(cond):
def resdec(f):
if cond:
print "profiling!"
return f
return resdec
# dummy function depending on both 'DO_DEBUG' and 'SOME_DEFAULT'
@do_profile(DO_DEBUG)
def dummy_function(bla=SOME_DEFAULT):
print bla
如果我运行python program.py
,我会得到以下输出:
1
1
2
这是预期的。第一个1
来自dummy_function
,第二个1
来自default_settings
导入functions
,2
来自我my_settings
重新导入dummy_function
。
有没有办法可以通过简单地使用my_settings
来覆盖from default_settings import *
所需的默认设置?我考虑过遗漏functions
中的NameError
行,但后来我遇到functions
。有没有办法从functions
导入,同时将所有变量传递到{{1}}?
答案 0 :(得分:5)
您需要以不同方式封装您的设置。现在,您使用两个不同的模块作为容器,用于两组不同的设置。然后导入这些模块中的所有名称,依靠from my_settings import *
覆盖由from default_settings import *
导入的名称。这是对import
的滥用。
一般情况下,我会说,当import
模块 时,定义的名称应该隐式重新定义。 from module import *
已经很糟糕,因为它在全局命名空间中隐式定义了一堆名称;使用另一个 *
导入隐式重新定义这些名称只是可怕的。
我的建议是使用字典存储设置,或使用设置类。在第一种情况下,你可以这样做:
# settings.py
default_settings = {'foo': True, 'bar': False}
my_settings = {'foo': False}
current_settings = default_settings.copy()
current_settings.update(my_settings)
现在任何模块都可以import settings
并像这样访问它们:
foo = settings.default_settings['foo']
bar = settings.current_settings['bar']
settings.current_settings['bar'] = True
对于已导入settings
的所有模块,可以看到对这些设置的任何更改。
更复杂的方法可能是使用Settings
类。 Settings
会定义一些默认值:
class Settings(object):
def __init__(self, foo=None, bar=None):
self.foo = foo if foo is not None else True
self.bar = bar if bar is not None else False
现在您可以创建各种自定义设置:
# settings.py
default_settings = Settings()
my_settings = Settings(foo=False)
current_settings = my_settings.copy()
current_settings.foo = False # pointless example
同样,如上所述,我们import settings
可以访问它们或进行更改:
# foo.py
import settings
bar = settings.current_settings.bar
settings.current_settings.foo = True
您甚至可以从Settings
继承以创建新的默认值:
class LocalSettings(Settings):
def __init__(self, foo=None, bar=None): # in Python 3,
super(LocalSettings, self).__init__(foo, bar) # super().__... works
self.foo = foo if foo is not None else True
等等。
答案 1 :(得分:2)
您的功能在导入时在functions.py
中定义 - 因此,如果(在program.py中)您
#start of file DO NOT "import functions" YET!!!
import default_settings
import my_settings
default_settings.DO_DEBUG=my_settings.DO_DEBUG
default_settings.SOME_DEFAULT=my_settings.SOME_DEFAULT
import functions
然后my_settings
的设置应该接管。我不知道这是否是你正在寻找的解决方案(它不适合我),但我看不到这个代码结构的任何其他选项。
修改强>
为了减轻手动重置所有设置的痛苦,您可以使用inspect
模块:
#start of file DO NOT "import functions" YET!!!
import default_settings
import my_settings
import inspect
#pull out all of "my_settings" and apply them to "default_settings",
# but only if they don't start with an underscore (reserved)
members=inspect.getmembers(my_settings)
for k,v in members:
if( not k.startswith('_') ):
setattr(default_settings,k,getattr(my_settings,k))
import functions
然而,这仍然不适合我 - 我不喜欢的是functions
的行为取决于你导入它的时间,这不是你通常在python中看到的。我认为您的代码可以从某种重组中受益。