我的应用程序从配置文件中读取许多常量。然后在整个程序的各个地方使用这些常量。这是一个例子:
import ConfigParser
config = ConfigParser.SafeConfigParser()
config.read('my.conf')
DB_HOST = config.get('DatabaseInfo', 'address')
DB_PORT_NUMBER = config.getint('DatabaseInfo', 'port_number')
DB_NUMBER = config.getint('DatabaseInfo', 'db_number')
IN_SERVICE = config.get('ServerInfo', 'in_service')
IN_DATA = config.get('ServerInfo', 'in_data')
等...
然后我在程序中定义了使用这些常量的函数。这是一个例子:
def connect_to_db():
return get_connection(DB_HOST, DB_PORT_NUMBER, DB_NUMBER)
有时,当我测试或使用REPL时,我不想使用配置文件中定义的值。
所以我改为将常量定义为参数:
def connect_to_db(db_host, db_port_number, db_number):
return get_connection(db_host, db_port_number, db_number)
然后当我的程序运行时,常量全部传入我的main
,需要调用其他函数然后调用函数并创建需要常量的类(所有可能在不同的模块中) :
def main(db_host, db_port_number, db_number, in_service, in_data):
intermediate_function(
db_host, db_port_number, db_number, other, parameters, here
)
other_intermediate_function(in_service, in_data, more, params, here)
# etc...
def intermediate_function(db_host, db_port_number, db_number):
# Other processing...
c = connect_to_db(db_host, db_port_number, db_number)
# Continued...
if __name__ == '__main__':
main(DB_HOST, DB_PORT_NUMBER, DB_NUMBER, IN_SERVICE, IN_DATA)
问题是,由于常量太多,这很快变得难以处理。如果我需要添加另一个常量,我有几个地方需要修改以确保我的代码不会中断。这是一场维护噩梦。
处理许多不同配置常量的Pythonic方法是什么,这样代码仍然易于修改并且易于测试?
答案 0 :(得分:2)
我的想法非常简单,使用可选的关键字参数。 这是一个小例子,我在说什么:
# collect, the constants to a dictionary,
# with the proper key names
d = dict(a=1, b=2, c=3)
# create functions, where you want to use the constants
# and use the same key-names as in dictionary, and also
# add '**kwargs' at the end of the attribute list
def func1(a, b, d=4, **kwargs):
print a, b, d
def func2(c, f=5, **kwargs):
print c, f
# now any time, you use the original dictionary
# as an argument for one of these functions, this
# will let the function select only those keywords
# that are used later
func1(**d)
# 1 2 4
func2(**d)
# 3 5
这个想法允许您在原始字典中仅在一个地方修改常量列表。 所以这回到了你的想法:
这是您的configuration.py
:
# Your parsing, reading and storing functions goes here..
# Now create your dictionary
constants = dict(
host = DB_HOST,
pnum = DB_PORT_NUMBER,
num = DB_NUMBER,
serv = IN_SERVICE,
data = IN_DATA
)
这是您的other_file.py
:
import configuration as cf
def main(host, pnum, num, serv, data, **kwargs):
intermediate_function(
host, pnum, num, 'other', 'params', 'here'
)
def intermediate_function(host, pnum, num, *args):
pass
# Now, you can call this function, with your
# dictionary as keyword arguments
if __name__ == '__main__':
main(**cf.constants)
虽然这有效,但我不建议使用此解决方案! 你的代码将难以维护,因为每次调用其中一个函数时,你传递常量字典,你只会看到“一个”参数:字典本身,它不是那么冗长。所以我相信,你应该考虑一个更好的代码架构,你使用更多确定性函数(返回“真实”值),并使用它们相互链接,所以你没有一直传递所有这些常量。但这是我的意见:))
修改强> 的
如果我上面提到的解决方案适合您,我也可以更好地了解如何存储和解析配置文件,并将其自动转换为字典。使用JSON而不是简单的.cfg
文件:
这将是您的conf.json
:
{
"host" : "DB_HOST",
"pnum" : "DB_PORT_NUMBER",
"num" : "DB_NUMBER",
"serv" : "IN_SERVICE",
"data" : "IN_DATA"
}
您的configuration.py
将如下所示:
import json
with open('conf.json') as conf:
# JSON parser will convert it to dictionary
constants = json.load(conf)