【问题标题】:What's the official way of storing settings for Python programs?存储 Python 程序设置的官方方式是什么?
【发布时间】:2010-11-01 05:30:47
【问题描述】:

Django 使用真正的 Python 文件进行设置,Trac 使用 .ini 文件,而其他一些软件使用 XML 文件来保存这些信息。

Guido 和/或 Python 社区对这些方法中的一种是否比另一种更有利?

【问题讨论】:

标签: python settings


【解决方案1】:

取决于主要的目标受众。

如果是程序员随便改文件,就用settings.py之类的python文件

如果是最终用户,请考虑 ini 文件。

【讨论】:

  • 典型的settings.py 文件是什么样的?
  • 我认为他指的是 Django settings.py 文件。它是一个有效的 Python 文件,其中包含字符串、元组、列表和其他变量的声明。
  • 我同意第一部分,但如果最终用户需要更改它,ConfigParser 可以读取您的内容。
【解决方案2】:

正如许多人所说,没有“官方”的方式。然而,有很多选择。今年有很多可用的选项a talk at PyCon

【讨论】:

【解决方案3】:

不知道这是否可以被认为是“官方的”,但它在标准库中:14.2. ConfigParser — Configuration file parser

显然,这不是一个通用的解决方案。只需使用最适合任务的任何东西,没有任何必要的复杂性(尤其是图灵完备性!想想自动或 GUI 配置器)。

【讨论】:

  • json 也在标准库中,还有各种 xml 处理模块
  • 当然 JSON 是标准的,但是这个模块被称为“配置文件解析器”是有原因的。我发现它非常适合阅读/写作,对于新手和非新手用户来说都很容易理解。
  • @SilentGhost JSON 格式不太适合人工编辑的配置文件。 --- 1. 不支持cmets。 2. 很多方括号和双引号可能会混淆人工编辑。
【解决方案4】:

我使用架子(http://docs.python.org/library/shelve.html):

shelf = shelve.open(filename)
shelf["users"] = ["David", "Abraham"]
shelf.sync() # Save

【讨论】:

  • 来自 docs,“因为 shelve 模块由 pickle 支持,所以从不受信任的来源加载货架是不安全的。与 pickle 一样,加载货架可以执行任意代码”。如果这个问题是为了指导新手,每个人都应该将他们指向 configparser 模块,否则指向 JSON 或自定义文件。 INI 文件部分比 JSON 更明确(可读),即使您美化它的代码。 [] 括号增加了一些粗体感,因此易于观看。
【解决方案5】:

还有一个选择,PyQt。 Qt 有一种独立于平台的方式来使用 QSettings 类存储设置。在幕后,在 Windows 上它使用注册表,在 linux 中它将设置存储在隐藏的 conf 文件中。 QSettings 非常好用,而且非常简洁。

【讨论】:

    【解决方案6】:

    据我所知,没有幸运的解决方案。存储应用程序设置的方式没有对错之分,xml、json 或所有类型的文件都可以,只要您对它感到满意。对于python,我个人使用pypref,它非常简单、跨平台且直接。

    pypref 非常有用,因为它可以存储静态和动态设置和首选项...

    from pypref import Preferences
    
    #  create singleton preferences instance
    pref = Preferences(filename="preferences_test.py")
    
    # create preferences dict
    pdict = {'preference 1': 1, 12345: 'I am a number'}
    
    # set preferences. This would automatically create preferences_test.py 
    # in your home directory. Go and check it.
    pref.set_preferences(pdict)
    
    # lets update the preferences. This would automatically update 
    # preferences_test.py file, you can verify that. 
    pref.update_preferences({'preference 1': 2})
    
    # lets get some preferences. This would return the value of the preference if
    # it is defined or default value if it is not.
    print pref.get('preference 1')
    
    # In some cases we must use raw strings. This is most likely needed when
    # working with paths in a windows systems or when a preference includes
    # especial characters. That's how to do it ...
    pref.update_preferences({'my path': " r'C:\Users\Me\Desktop' "})
    
    # Sometimes preferences to change dynamically or to be evaluated real time.
    # This also can be done by using dynamic property. In this example password
    # generator preference is set using uuid module. dynamic dictionary
    # must include all modules name that must be imported upon evaluating
    # a dynamic preference
    pre = {'password generator': "str(uuid.uuid1())"}
    dyn = {'password generator': ['uuid',]}
    pref.update_preferences(preferences=pre, dynamic=dyn)
    
    # lets pull 'password generator' preferences twice and notice how
    # passwords are different at every pull
    print pref.get('password generator')
    print pref.get('password generator')
    
    # those preferences can be accessed later. Let's simulate that by creating
    # another preferences instances which will automatically detect the 
    # existance of a preferences file and connect to it
    newPref = Preferences(filename="preferences_test.py")
    
    # let's print 'my path' preference
    print newPref.get('my path')
    

    【讨论】:

    • pypref 完全震撼。使用起来非常简单直接(它让我想起了 Android 的 SharedPreferences,也许这就是原因)。祝贺你的出色工作!
    • 很遗憾 Python 3 不支持
    【解决方案7】:

    我不确定是否有“官方”方式(Python 禅宗中没有提到 :))- 我自己倾向于使用 Config Parser 模块,我认为您会发现这很常见。我更喜欢 python 文件方法,因为你可以写回它并根据需要动态重新加载。

    【讨论】:

      【解决方案8】:

      这在很大程度上取决于您的配置有多复杂。如果您正在做一个简单的键值映射,并且您希望能够使用文本编辑器编辑设置,我认为 ConfigParser 是您的最佳选择。

      如果您的设置很复杂并且包括列表和嵌套数据结构,我会使用 XML 或 JSON 并创建一个配置编辑器。

      对于非常复杂的事情,最终用户不希望更改太多设置,或者更受信任,只需创建一组 Python 类并评估 Python 脚本以获取配置。

      【讨论】:

        【解决方案9】:

        使用json 模块是最简单的方法之一。 将文件保存在config.json 中,详细信息如下所示。

        在json文件中保存数据:

        {
        
            "john"  : {
                "number" : "948075049" , 
                "password":"thisisit" 
            }    
        }
        

        从 json 文件中读取:

        import json
        
        #open the config.json file 
        
        with open('config.json') as f:
            mydata = json.load(f) ; 
        
        #Now mydata is a python dictionary 
        
        print("username is " , mydata.get('john').get('number') , " password is " , mydata.get('john').get('password')) ;
        

        【讨论】:

        • 请注意,mydata.get('john').get('number') 不是一个好的代码。如果数据中没有john 键,则mydata.get('john') 将返回None.get('number') 将引发异常。使用.get 假设您想优雅地处理丢失的数据;所以最好这样做:mydata.get('john', {}).get('number') - 这不会导致异常,除非mydata 本身不是dict
        【解决方案10】:

        对于我喜欢使用操作系统环境变量的 Web 应用程序:os.environ.get('CONFIG_OPTION')

        这对于部署之间不同的设置特别有效。您可以在此处阅读有关使用 env vars 背后原理的更多信息:http://www.12factor.net/config

        当然,这仅适用于只读值,因为对环境的更改通常不是持久的。但如果您不需要写权限,它们是一个非常好的解决方案。

        【讨论】:

        • 不错,但是当有很多变量要设置时,使用 Django 方式可能会更方便:将其存储到文件中并根据单个环境变量设置不同的文件(在 django 中,DJANGO_SETTINGS_MODULE )。这样你也可以拥有动态和可写的值。
        • 如果您正在使用这种方法,那么您可能还想看看github.com/theskumar/python-dotenv
        【解决方案11】:

        不是官方的,但这种方式适用于我所有的 Python 项目。

        pip install python-settings
        

        这里的文档:https://github.com/charlsagente/python-settings

        您需要一个包含所有已定义常量的 settings.py 文件,例如:

        # settings.py
        
        DATABASE_HOST = '10.0.0.1'
        

        然后您需要设置一个环境变量(导出 SETTINGS_MODULE=settings)或手动调用配置方法:

        # something_else.py
        
        from python_settings import settings
        from . import settings as my_local_settings
        
        settings.configure(my_local_settings) # configure() receives a python module
        

        该实用程序还支持对重负载对象进行延迟初始化,因此当您运行 python 项目时,它加载速度更快,因为它只在需要时评估设置变量

        # settings.py
        
        from python_settings import LazySetting
        from my_awesome_library import HeavyInitializationClass # Heavy to initialize object
        
        LAZY_INITIALIZATION = LazySetting(HeavyInitializationClass, "127.0.0.1:4222") 
        # LazySetting(Class, *args, **kwargs)
        

        只需配置一次,然后在需要的地方调用您的变量:

        # my_awesome_file.py
        
        from python_settings import settings 
        
        print(settings.DATABASE_HOST) # Will print '10.0.0.1'
        

        【讨论】:

        • 这个库使用 Python 文件来存储配置。此选项具有巨大的安全缺陷,因为配置文件可能包含任何可执行代码 - 可能是恶意的或无意中以错误的方式失败。
        【解决方案12】:

        这样更方便。没有官方说法。但是使用 XML 文件是有意义的,因为它们可以被各种其他应用程序/库操作。

        【讨论】:

        • json、ini文件等也可以这样说
        • @Darren:如果您使用的是 Python 2.5 或更高版本,则不正确(因为 ElementTree)
        • @becomingGuru:XML 设计目标 6:“XML 文档应该易于阅读且相当清晰。”
        • @S. Lott - 当然他们应该这样做,但这并不意味着他们真的是。您必须承认编辑 ini 或属性文件比编辑 xml 文档要容易得多。
        • @Shane C. Mason:人类应该读/写 XML。实际上,这确实很难,因此我很少使用 XML。我使用 JSON 或 CSV 文件——更容易编辑。但是@becomingGuru 的评论——在狭义的技术意义上——是不正确的。
        【解决方案13】:

        为什么Guido会祝福他范围之外的东西?不,没有什么特别的祝福。

        【讨论】:

        • 赞成,因为您实际上回答了 OP 的问题(“没有什么特别的祝福”)。反对意见可能来自您答案的第一部分:让社区共享“最佳实践”确实有助于开始使用新语言/新项目...
        • 我理解 Guido 的裁决在核心、stdlib 开发等方面的作用,但问题是关于基本使用,很难定义好的实践。
        猜你喜欢
        • 2011-11-26
        • 1970-01-01
        • 2020-10-29
        • 2010-09-06
        • 1970-01-01
        • 2018-02-10
        • 1970-01-01
        • 2010-12-05
        • 2012-08-17
        相关资源
        最近更新 更多