我搜索了 stackoverflow,但似乎找不到与我类似的答案。
大多数人都想解析重复的键,但我想写它们。 (我更喜欢使用异步文件写入来完成此操作,但那是另一个故事了)
专门用于 systemd-networkd 配置。它们使用 ini 格式,但允许重复的键。例如
[Match]
Name=eth0
[Network]
Address=10.0.0.12/24
Gateway=10.0.0.1
DNS=1.1.1.1
DNS=8.8.8.8
我希望能够这样写:
conf = ConfigParser()
conf.optionxform = str
conf["Match"] = {"Name": "eth0"}
conf["Network"] = {
"DHCP": "no",
"Address": "10.0.0.12/24",
"Gateway": "10.0.0.1",
"Dns": ["1.1.1.1", "8.8.8.8"],
}
但是,显然,这会被写成文字字符串。
我写了下面的令人厌恶的东西来完成这项工作,但肯定有一个更简单/更理智的方法?
from configparser import ConfigParser
import ast
class CustomParser(ConfigParser):
def _write_section(self, fp, section_name, section_items, delimiter):
"""Write a single section to the specified `fp`."""
def write_item(item):
item = self._interpolation.before_write(
self, section_name, key, item
)
if item is not None or not self._allow_no_value:
item = delimiter + str(item).replace("\n", "\n\t")
else:
item = ""
fp.write("{}{}\n".format(key, item))
fp.write("[{}]\n".format(section_name))
for key, value in section_items:
parsed = None
try:
parsed = ast.literal_eval(value)
except Exception:
pass
if isinstance(parsed, list):
for list_item in parsed:
write_item(list_item)
else:
write_item(value)
fp.write("\n")
一种解决方案是创建自定义字典并使用该字典初始化
ConfigParser()
(构造函数中的dict_type=
参数):
import sys
from ast import literal_eval
from configparser import ConfigParser
class my_dict(dict):
def items(self):
for k, v in super().items():
if (
v.startswith("[")
and v.endswith("]")
and isinstance(lst := literal_eval(v), list)
):
for i in lst:
yield k, i
else:
yield k, v
conf = ConfigParser(dict_type=my_dict)
conf["Match"] = {"Name": "eth0"}
conf["Network"] = {
"DHCP": "no",
"Address": "10.0.0.12/24",
"Gateway": "10.0.0.1",
"Dns": ["1.1.1.1", "8.8.8.8"],
}
conf.write(sys.stdout)
打印:
[Match]
name = eth0
[Network]
dhcp = no
address = 10.0.0.12/24
gateway = 10.0.0.1
dns = 1.1.1.1
dns = 8.8.8.8