如何跨模块存储应用程序设置

use*_*235 8 python app-config global-variables

我收到了一位离开我们公司的开发人员的项目.不太复杂,但看起来不太好.所以这里有一个问题:应用程序有一些模块,一个是存储某些应用程序的"设置".选项(不是所有可能的选项,简单地说两个:foobar).启动应用程序时,它从命令行读取选项(使用argparse):

parser.add_argument('--foo', action='store_true')
parser.add_argument('--bar', action='store_true')
parser.add_argument('--baz', action='store_true')
Run Code Online (Sandbox Code Playgroud)

然后它执行这个令人讨厌的事情:

for name, val in parser.parse_args(sys.argv[1:])._get_kwargs():
    setattr(sys.modules['settings'], name, val)
Run Code Online (Sandbox Code Playgroud)

第一:我认为这是肮脏的,非pythonic黑客.第二,使用这样的代码简直不方便,因为当我需要使用时settings.baz,IDE会抱怨它不存在.此hack的目的是使命令行解析的选项在应用程序中进一步使用的所有模块中可用.

我正在考虑像singleton模式这样的东西,但我只在PHP中使用过一次,并且不知道python中是否有这个正确的解决方案.即使是这样,有人可以举例吗?

我是python中的菜鸟,所以请对我友好:)谢谢.

ps我很抱歉我的英语可能出错

mar*_*eau 7

Python 中的模块单例对象,使用一个来存储其他模块使用的设置将是一个非常Pythonic

"讨厌的东西"的第二行只是设置一个名为的模块的属性,settings所以并没有那么糟糕.更糟糕的是_get_kwargs()第一行的一部分是访问argparse.Namespace返回的对象的私有属性,parser.parse_args()以获取从命令行解析的设置的名称和值.稍微好一点的方法可能是这样的:

import settings  # possibly empty .py file

for name, val in vars(parser.parse_args(sys.argv[1:])).iteritems():
    setattr(settings, name, val)
Run Code Online (Sandbox Code Playgroud)

但是,这不会解决您的IDE问题,因为IDE不知道动态添加的设置的名称.解决这个问题的一种简单方法是使用settings.py模块中的某种默认值来定义所有可能的属性,而不是使用空值.

第一次import编辑模块时,会将其条目添加到sys.modules字典中,其名称为键,types.ModuleType值为实例.后续的imports将首先检查它的条目是否已经存在并且如果它存在则将跳过重新加载文件 - 这就是我声称它们基本上是单例对象的原因.对其属性进行的修改将立即显示给已导入它的其他模块或之后执行此操作,因此它通常是应用程序中的良好数据共享机制.

  • FWIW还有一节[如何在模块之间共享全局变量?](https://docs.python.org/3/faq/programming.html#how-do-i-share-global-variables-across-具有相同建议的当前Python 3文档中的“模块”)(称为“规范”方法)。 (2认同)