如何在 Python 中保存简单的设置/配置文件?

问题描述 投票:0回答:8

我不在乎它是 JSONpickleYAML 还是其他。

我见过的所有其他实现都不向前兼容,所以如果我有一个配置文件,在代码中添加一个新密钥,然后加载该配置文件,它就会崩溃。

有没有简单的方法可以做到这一点?

python json settings config ini
8个回答
284
投票

python中的配置文件

根据所需的文件格式,有多种方法可以执行此操作。

ConfigParser [.ini 格式]

我会使用标准的 configparser 方法,除非有令人信服的理由使用不同的格式。

像这样编写文件:

# python 2.x
# from ConfigParser import SafeConfigParser
# config = SafeConfigParser()

# python 3.x
from configparser import ConfigParser
config = ConfigParser()

config.read('config.ini')
config.add_section('main')
config.set('main', 'key1', 'value1')
config.set('main', 'key2', 'value2')
config.set('main', 'key3', 'value3')

with open('config.ini', 'w') as f:
    config.write(f)

文件格式非常简单,部分用方括号标记:

[main]
key1 = value1
key2 = value2
key3 = value3

可以像这样从文件中提取值:

# python 2.x
# from ConfigParser import SafeConfigParser
# config = SafeConfigParser()

# python 3.x
from configparser import ConfigParser
config = ConfigParser()

config.read('config.ini')

print(config.get('main', 'key1')) # -> "value1"
print(config.get('main', 'key2')) # -> "value2"
print(config.get('main', 'key3')) # -> "value3"

# getfloat() raises an exception if the value is not a float
a_float = config.getfloat('main', 'a_float')

# getint() and getboolean() also do this for their respective types
an_int = config.getint('main', 'an_int')

JSON [.json 格式]

JSON 数据可能非常复杂,但具有高度可移植的优点。

将数据写入文件:

import json

config = {"key1": "value1", "key2": "value2"}

with open('config1.json', 'w') as f:
    json.dump(config, f)

从文件中读取数据:

import json

with open('config.json', 'r') as f:
    config = json.load(f)

#edit the data
config['key3'] = 'value3'

#write it back to the file
with open('config.json', 'w') as f:
    json.dump(config, f)

YAML

在此答案中提供了一个基本的 YAML 示例。更多详细信息可以在 pyYAML 网站上找到。


20
投票
对于简单的配置文件,我更喜欢 JSON 文件,例如文件

conf.json:

{ "version": 1, "bind": { "address": "127.0.0.1", "port": 8080 }, "data": { "a": [1, 2, 3], "b": 2.5 } }
然后创建这个自定义 JSON 配置读取器:

import json class Dict(dict): """dot.notation access to dictionary attributes""" __getattr__ = dict.__getitem__ __setattr__ = dict.__setitem__ __delattr__ = dict.__delitem__ class Config(object): @staticmethod def __load__(data): if type(data) is dict: return Config.load_dict(data) elif type(data) is list: return Config.load_list(data) else: return data @staticmethod def load_dict(data: dict): result = Dict() for key, value in data.items(): result[key] = Config.__load__(value) return result @staticmethod def load_list(data: list): result = [Config.__load__(item) for item in data] return result @staticmethod def load_json(path: str): with open(path, "r") as f: result = Config.__load__(json.loads(f.read())) return result
最后,使用命令加载它:

conf = Configuration.load_json('conf.json')
现在您可以使用点“.”访问您的配置,例如:

print(conf.version) print(conf.bind.address) print(conf.bind.port) print(conf.data.a) print(conf.data.b)
    

13
投票

ConfigParser 基本示例

文件可以像这样加载和使用:

#!/usr/bin/env python import ConfigParser import io # Load the configuration file with open("config.yml") as f: sample_config = f.read() config = ConfigParser.RawConfigParser(allow_no_value=True) config.readfp(io.BytesIO(sample_config)) # List all contents print("List all contents") for section in config.sections(): print("Section: %s" % section) for options in config.options(section): print("x %s:::%s:::%s" % (options, config.get(section, options), str(type(options)))) # Print some contents print("\nPrint some contents") print(config.get('other', 'use_anonymous')) # Just get the value print(config.getboolean('other', 'use_anonymous')) # You know the datatype?
输出

List all contents Section: mysql x host:::localhost:::<type 'str'> x user:::root:::<type 'str'> x passwd:::my secret password:::<type 'str'> x db:::write-math:::<type 'str'> Section: other x preprocessing_queue:::["preprocessing.scale_and_center", "preprocessing.dot_reduction", "preprocessing.connect_lines"]:::<type 'str'> x use_anonymous:::yes:::<type 'str'> Print some contents yes True
如您所见,您可以使用易于读写的标准数据格式。 

getbooleangetint 等方法允许您获取数据类型而不是简单的字符串。

写入配置

import os configfile_name = "config.yaml" # Check if there is already a configuration file if not os.path.isfile(configfile_name): # Create the configuration file as it doesn't exist yet cfgfile = open(configfile_name, 'w') # Add content to the file Config = ConfigParser.ConfigParser() Config.add_section('mysql') Config.set('mysql', 'host', 'localhost') Config.set('mysql', 'user', 'root') Config.set('mysql', 'passwd', 'my secret password') Config.set('mysql', 'db', 'write-math') Config.add_section('other') Config.set('other', 'preprocessing_queue', ['preprocessing.scale_and_center', 'preprocessing.dot_reduction', 'preprocessing.connect_lines']) Config.set('other', 'use_anonymous', True) Config.write(cfgfile) cfgfile.close()
结果

[mysql] host = localhost user = root passwd = my secret password db = write-math [other] preprocessing_queue = ['preprocessing.scale_and_center', 'preprocessing.dot_reduction', 'preprocessing.connect_lines'] use_anonymous = True

XML 基本示例

Python 社区似乎根本不使用配置文件。然而,解析/编写 XML 很容易,并且使用 Python 有很多可能性可以做到这一点。一是

美汤

from BeautifulSoup import BeautifulSoup with open("config.xml") as f: content = f.read() y = BeautifulSoup(content) print(y.mysql.host.contents[0]) for tag in y.other.preprocessing_queue: print(tag)
其中 

config.xml 文件可能如下所示:

<config> <mysql> <host>localhost</host> <user>root</user> <passwd>my secret password</passwd> <db>write-math</db> </mysql> <other> <preprocessing_queue> <li>preprocessing.scale_and_center</li> <li>preprocessing.dot_reduction</li> <li>preprocessing.connect_lines</li> </preprocessing_queue> <use_anonymous value="true" /> </other> </config>
    

11
投票
如果您想使用 INI 文件之类的东西来保存设置,请考虑使用

configparser,它从文本文件加载键值对,并且可以轻松写回文件。

INI 文件的格式为:

[Section] key = value key with spaces = somevalue
    

2
投票
保存并加载字典。您将拥有任意键、值以及任意数量的键、值对。


2
投票
我面临着同样的问题,但此外我想从硬编码字段中读取配置变量,以防配置文件不存在。

我的变体:

import json class Configurator: def __init__(self): # Hard coded values if config file doesn't exist self.alpha: int = 42 self.bravo: float = 3.14 self.charlie: str = "8.8.8.8" self.delta: list = ["Lorem", "ipsum", "dolor", "sit", "amet"] self.echo: dict = {"Winter": "is coming"} def read_config_file(self, config_file_name: str = "config.json"): try: with open(config_file_name) as conf_file: for k, v in json.loads(conf_file.read()).items(): setattr(self, k, v) except Exception as e: print(f"Error was detected while reading {config_file_name}: {str(e)}. Hard coded values will be applied") def save_config_file(self, config_file_name: str = "config.json"): try: conf_items = {k: v for k, v in vars(self).items() if isinstance(v, (int, float, str, list, dict))} with open(config_file_name, "w") as conf_file: json.dump(conf_items, conf_file, sort_keys=False, indent=2) except Exception as e: print(f"Error was detected while saving {config_file_name}: {str(e)}")
from configurator import Configurator

if __name__ == '__main__':
    conf = Configurator()

    # Read the configuration (values from file or hard coded values if file doesn't exist)
    conf.read_config_file()

    # Using values from configuration
    a = conf.alpha

    # Changing values in the configuration
    conf.bravo += 1

    # Save changed configuration to the file
    conf.save_config_file()
如果配置文件不存在,它会在第一次调用

conf.save_config_file()后出现。如果之后更改 config.json,文件中的变量下次必须“击败”硬编码变量。

代码有点hacky,使用前先测试一下。


0
投票
尝试使用

ReadSettings

from readsettings import ReadSettings data = ReadSettings("settings.json") # Load or create any json, yml, yaml or toml file data["name"] = "value" # Set "name" to "value" data["name"] # Returns: "value"
    

0
投票
尝试使用

cfg4py

    分层设计,支持多种环境,永远不会混淆开发设置和生产站点设置。
  1. 代码完成。 Cfg4py 会将您的
  2. YAML 内容转换为 Python 类,然后在您键入代码时即可使用 代码补全
  3. 还有更多...

免责声明:我是该模块的作者

© www.soinside.com 2019 - 2024. All rights reserved.