0

我的应用程序从配置文件中读取了许多常量。然后在整个程序的各个地方使用这些常量。这是一个例子:

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')

ETC...

然后,我在整个程序中定义了使用这些常量的函数。这是一个例子:

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 方式是什么,以便代码仍然易于修改和易于测试?

4

1 回答 1

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)
于 2013-06-20T10:17:59.950 回答