【问题标题】:Why .conf file instead config.py file?为什么 .conf 文件而不是 config.py 文件?
【发布时间】:2017-04-23 06:37:44
【问题描述】:

我正在查看几个 python 项目。几乎每个好的 python 项目通常都有一个 app.confapp.ini 文件用于他们的配置管理。之后,他们使用类似configparser.py 的模块从app.conf 文件中提取配置信息。最后,他们不得不以某种方式使用 .py 模块中的值。

我们来看一个例子

app.conf

[BREED]
beagle=dog
ragdoll=cat
deilenaar=rabbit
cockatoo=parrot

app.py

​​>
#!/usr/bin/env python
#-*- coding: utf-8 -*-

import configparser

config = configparser.ConfigParser()
config.read('app.conf')
print(config['BREED']['cockatoo']) # prints parrot

那么为什么不使用字典并使用该字典来代替以下内容。

#!usr/bin/env python
# -*- coding: utf-8 -*-

config = {'BREED': {'beagle': 'dog',
                    'ragdoll': 'cat',
                    'deilenaar': 'rabbit',
                    'cockatoo': 'parrot'}}
print(config['BREED']['cockatoo']) # prints parrot

如果我们需要全局使用config,那么我们将把变量放在包根目录下的__init__.py 中。这样我们就不必再读取 app.conf 文件了。

我相信使用 app.conf 文件是有充分理由的。那是什么原因呢?

【问题讨论】:

  • 在 Python 上下文之外重用配置文件来启动;可执行代码与用户可配置配置的解耦使得最终用户可以在不修改源代码的情况下进行操作,还可以重新定位这些配置文件,因为程序可以从多个位置读取。
  • 我已经提到,如果我们的应用程序需要使用来自多个位置的配置信息,那么我们会将配置信息放在单独的 .py 文件中,关于最终用户的事情:为什么最终用户需要更改源代码或配置文件?
  • 注意:Django 确实使用 Python 配置文件,但由于上述原因,这并不是一个好的决定。

标签: python configuration config configuration-files


【解决方案1】:

因此,用户无需编辑源代码即可更改.conf 文件中的值。还允许将设置保存到.conf 并稍后在不编辑源文件的情况下读取。

【讨论】:

    【解决方案2】:

    从配置文件中读取时,程序员可以选择如何处理文件格式中的错误。无法解析特定的行?分配一个默认值。想要宽容并接受没有结束引号的字符串吗?去吧。

    另一方面,Python 模块是全有或全无。如果文件的语法不完美,您将一无所获

    【讨论】:

    • 好吧,就是这样,但接受没有右引号的字符串不是很糟糕吗?
    • 如果您将字符串定义为以引号开头并以匹配的引号或换行符结尾...不。我想这将是一个罕见的用例,但我见过更奇怪的文件格式......
    • 如果你举一个带有小代码的例子会很有帮助,因为我没有清楚地了解你想说什么。
    【解决方案3】:

    安全性。

    我同意你的观点,但安全无法应付 config.py,除了可能使用包装器,在这种情况下可以称为 config_parser.py

    假设在整个代码中都导入了 config.py

    from config.dir import config

    这一行执行 config.py!

    这意味着任何攻击者都可以在那里做任何事情,可能需要提升权限。

    这足以让我不这样做。


    这是我的样板配置

    class ConfigProvider(object):
        _config = None
    
        @staticmethod
        def get_config():
            if ConfigProvider._config is None:
                ConfigProvider._config = ConfigParser(config_path).parse()
            return ConfigProvider._config
    
    
    class ConfigParser(object):
        def __init__(self, config_path):
            self._config_path = config_path
    
        def parse(self):
            parsed = None
            with open(self._config_path, 'r') as stream:
                try:
                    # https://stackoverflow.com/questions/2352181/how-to-use-a-dot-to-access-members-of-dictionary
                    parsed = Map(yaml.safe_load(stream))
                except yaml.YAMLError as exc:
                    traceback.print_exc(exc)
    
            return parsed
    
    
    class Map(dict):
        # https://stackoverflow.com/questions/2352181/how-to-use-a-dot-to-access-members-of-dictionary
        """
        Example:
        m = Map({'first_name': 'Eduardo'}, last_name='Pool', age=24, sports=['Soccer'])
        """
        def __init__(self, *args, **kwargs):
            super(Map, self).__init__(*args, **kwargs)
            for arg in args:
                if isinstance(arg, dict):
                    for k, v in arg.items():
                        self[k] = v
                        if isinstance(v, dict):
                            self[k] = Map(v)
    
            if kwargs:
                # for python 3 use kwargs.items()
                for k, v in kwargs.items():
                    self[k] = v
                    if isinstance(v, dict):
                        self[k] = Map(v)
    
        def __getattr__(self, attr):
            return self.get(attr)
    
        def __setattr__(self, key, value):
            self.__setitem__(key, value)
    
        def __setitem__(self, key, value):
            super(Map, self).__setitem__(key, value)
            self.__dict__.update({key: value})
    
        def __delattr__(self, item):
            self.__delitem__(item)
    
        def __delitem__(self, key):
            super(Map, self).__delitem__(key)
            del self.__dict__[key]
    
        def __getstate__(self):  # required for successful pickling
            return self.__dict__
    
        def __setstate__(self, d):  # required for successful pickling
            self.__dict__.update(d)
    
    
    config = ConfigProvider.get_config()
    
    

    用户总是只需要一行来获取他们的配置。

    当然不如 .py 方便,但安全性很重要。

    注意 yaml 上的 safe_load

    【讨论】:

      猜你喜欢
      • 2011-02-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-14
      • 1970-01-01
      相关资源
      最近更新 更多