2

我试图弄清楚如何覆盖在某些模块中定义的函数的默认值。考虑这段代码(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_settingsinside的导入functions2是我重新导入的结果my_settings

dummy_function有没有一种方法可以通过简单地使用来覆盖所需的默认设置my_settings?我想把from default_settings import *线路省掉functions,但后来我遇到了NameError。有没有办法导入functions并同时将所有变量传递到functions?

4

2 回答 2

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

等等。

于 2012-05-30T15:14:10.097 回答
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 中看到的。我认为您的代码可以从某种重组中受益。

于 2012-05-30T14:45:09.310 回答