在 ConfigParser 中如何只获取部分局部选项?
In ConfigParser how to get only section-local options?
考虑以下名为 foo.py
的 MWE:
#!/usr/bin/env python3
from configparser import ConfigParser
if __name__ == "__main__":
cfg = ConfigParser()
with open("foo.ini") as ini:
cfg.read_file(ini)
for section in cfg.sections():
print("[%s]" % (section))
for option, value in cfg.items(section):
print("%s = %s" % (option, value))
... 以及随附的 foo.ini
:
[DEFAULT]
basedir = /foo/bar
sourcedir = %(basedir)s/baz
[task:1]
sourcedir = /usr
workdir = %(sourcedir)s/src
[task:2]
hdrdir = %(sourcedir)s/include
脚本将在 运行 时产生以下内容:
[task:1]
basedir = /foo/bar
sourcedir = /usr
workdir = /usr/src
[task:2]
basedir = /foo/bar
sourcedir = /foo/bar/baz
hdrdir = /foo/bar/baz/include
期望的结果是专门迭代(插值)选项(通过ConfigParser.items()
)给定部分的本地。
将 raw=True
传递给 ConfigParser.items()
不会影响项目列表,只是值 不是 被插值(无论如何不是期望的结果)。
现在我可以在初始脚本的这个修改版本中做类似的事情:
#!/usr/bin/env python3
from configparser import ConfigParser
if __name__ == "__main__":
cfg = ConfigParser()
with open("foo.ini") as ini:
cfg.read_file(ini)
print("; sections: %s" % (cfg.sections()))
print("; defaults: %s" % (cfg.defaults()))
for section in cfg.sections():
print("[%s]" % (section))
print("; options = %s" % (cfg.options(section)))
for option, value in cfg.items(section):
if option in cfg.defaults():
# can't use cfg.defaults()[option] ... that's the raw value
if cfg[cfg.default_section][option] == value:
continue
print("%s = %s" % (option, value))
... 产生:
; sections: ['task:1', 'task:2']
; defaults: OrderedDict([('basedir', '/foo/bar'), ('sourcedir', '%(basedir)s/baz')])
[task:1]
; options = ['sourcedir', 'workdir', 'basedir']
sourcedir = /usr
workdir = /usr/src
[task:2]
; options = ['hdrdir', 'basedir', 'sourcedir']
hdrdir = /foo/bar/baz/include
乍一看它可以工作,但会过滤掉与全局同名选项具有相同值的部分局部选项。
现在这看起来可能只是一个表面问题,但在我的例子中,仍然存在语义差异,选项是否存在于本地部分内部,或者它的值是否从默认部分继承(考虑多个文件, 多个继承选项 ...)。重点是这是一种天真的方法,对我不起作用。
所以问题是: 我怎样才能只 .ini
文件的一部分中的选项,没有所有这些全局继承选项?
有没有办法在不深入 configparser
模块的内部并篡改非 public 方法和东西的情况下做到这一点?
检查 code of ConfigParser
我没有看到 public API 可以这样做。事实上,ConfigParser
中的任何方法都使用默认值扩展了给定的部分。
我看到的唯一直接的方法是更改配置中的默认部分 或 ConfigParser
constructor 中的(default_section
参数):
if __name__ == "__main__":
cfg = ConfigParser(default_section=None)
# (...)
然而,副作用是自动 "default" 机制将不再适用于此实例化 ConfigParser
。但是你仍然可以自己做回退机制:
cfg = ConfigParser(default_section=None)
cfg.get(mysection, myoption, fallback=cfg.get('DEFAULT', myoption))
此外,值的插值在 DEFAULT
部分不起作用。但是你可以使用 ExtendedInterpolation
.
完整示例:
# test.py
from configparser import ConfigParser, DEFAULTSECT, ExtendedInterpolation
if __name__ == '__main__':
cfg = ConfigParser(default_section=None, interpolation=ExtendedInterpolation())
with open('test.ini') as ini:
cfg.read_file(ini)
for section in cfg.sections():
if section == DEFAULTSECT:
continue
print('[%s]' % (section))
for key, value in cfg.items(section):
print('%s = %s' % (key, value))
# test.ini
[DEFAULT]
foo=bar
[section]
key="value ${DEFAULT:foo}"
编辑:
如果 - 重命名
DEFAULT
部分的目的是配置默认值,则这不是一个好主意。我勾选这个选项。
- 将
default_section
设置为 None
而不是 "whatever"
- 添加完整的代码示例
- 添加有关 ExtendedInterpolation 的详细信息
考虑以下名为 foo.py
的 MWE:
#!/usr/bin/env python3
from configparser import ConfigParser
if __name__ == "__main__":
cfg = ConfigParser()
with open("foo.ini") as ini:
cfg.read_file(ini)
for section in cfg.sections():
print("[%s]" % (section))
for option, value in cfg.items(section):
print("%s = %s" % (option, value))
... 以及随附的 foo.ini
:
[DEFAULT]
basedir = /foo/bar
sourcedir = %(basedir)s/baz
[task:1]
sourcedir = /usr
workdir = %(sourcedir)s/src
[task:2]
hdrdir = %(sourcedir)s/include
脚本将在 运行 时产生以下内容:
[task:1]
basedir = /foo/bar
sourcedir = /usr
workdir = /usr/src
[task:2]
basedir = /foo/bar
sourcedir = /foo/bar/baz
hdrdir = /foo/bar/baz/include
期望的结果是专门迭代(插值)选项(通过ConfigParser.items()
)给定部分的本地。
将 raw=True
传递给 ConfigParser.items()
不会影响项目列表,只是值 不是 被插值(无论如何不是期望的结果)。
现在我可以在初始脚本的这个修改版本中做类似的事情:
#!/usr/bin/env python3
from configparser import ConfigParser
if __name__ == "__main__":
cfg = ConfigParser()
with open("foo.ini") as ini:
cfg.read_file(ini)
print("; sections: %s" % (cfg.sections()))
print("; defaults: %s" % (cfg.defaults()))
for section in cfg.sections():
print("[%s]" % (section))
print("; options = %s" % (cfg.options(section)))
for option, value in cfg.items(section):
if option in cfg.defaults():
# can't use cfg.defaults()[option] ... that's the raw value
if cfg[cfg.default_section][option] == value:
continue
print("%s = %s" % (option, value))
... 产生:
; sections: ['task:1', 'task:2']
; defaults: OrderedDict([('basedir', '/foo/bar'), ('sourcedir', '%(basedir)s/baz')])
[task:1]
; options = ['sourcedir', 'workdir', 'basedir']
sourcedir = /usr
workdir = /usr/src
[task:2]
; options = ['hdrdir', 'basedir', 'sourcedir']
hdrdir = /foo/bar/baz/include
乍一看它可以工作,但会过滤掉与全局同名选项具有相同值的部分局部选项。
现在这看起来可能只是一个表面问题,但在我的例子中,仍然存在语义差异,选项是否存在于本地部分内部,或者它的值是否从默认部分继承(考虑多个文件, 多个继承选项 ...)。重点是这是一种天真的方法,对我不起作用。
所以问题是: 我怎样才能只 .ini
文件的一部分中的选项,没有所有这些全局继承选项?
有没有办法在不深入 configparser
模块的内部并篡改非 public 方法和东西的情况下做到这一点?
检查 code of ConfigParser
我没有看到 public API 可以这样做。事实上,ConfigParser
中的任何方法都使用默认值扩展了给定的部分。
我看到的唯一直接的方法是更改配置中的默认部分 或 (ConfigParser
constructor 中的default_section
参数):
if __name__ == "__main__":
cfg = ConfigParser(default_section=None)
# (...)
然而,副作用是自动 "default" 机制将不再适用于此实例化 ConfigParser
。但是你仍然可以自己做回退机制:
cfg = ConfigParser(default_section=None)
cfg.get(mysection, myoption, fallback=cfg.get('DEFAULT', myoption))
此外,值的插值在 DEFAULT
部分不起作用。但是你可以使用 ExtendedInterpolation
.
完整示例:
# test.py
from configparser import ConfigParser, DEFAULTSECT, ExtendedInterpolation
if __name__ == '__main__':
cfg = ConfigParser(default_section=None, interpolation=ExtendedInterpolation())
with open('test.ini') as ini:
cfg.read_file(ini)
for section in cfg.sections():
if section == DEFAULTSECT:
continue
print('[%s]' % (section))
for key, value in cfg.items(section):
print('%s = %s' % (key, value))
# test.ini
[DEFAULT]
foo=bar
[section]
key="value ${DEFAULT:foo}"
编辑:
-
如果
- 重命名
DEFAULT
部分的目的是配置默认值,则这不是一个好主意。我勾选这个选项。 - 将
default_section
设置为None
而不是"whatever"
- 添加完整的代码示例
- 添加有关 ExtendedInterpolation 的详细信息