如何从 Python ConfigParser .items() 中排除默认值?

发布于 2024-08-19 22:10:55 字数 1416 浏览 16 评论 0 原文

我使用 ConfigParser 从配置文件加载数据,如下所示:

test.conf:

[myfiles]
fileone: %(datadir)s/somefile.foo
filetwo: %(datadir)s/nudderfile.foo

load.py:

import ConfigParser

config = ConfigParser.ConfigParser({'datadir': '/tmp'})
config.read('test.conf')

print config.items('myfiles')
print config.get('myfiles', 'datadir')

输出:

$ python load.py 
[('datadir', '/tmp'), ('filetwo', '/tmp/nudderfile.foo'), ('fileone', '/tmp/somefile.foo')]
/tmp

我令人惊讶的是变量替换 ('datadir', '/tmp') 的默认值显示为 .items().get() 的一部分 返回,就像它们是配置文件中的值一样。这种行为是预期的吗?有什么解决方法,以便我可以简单地迭代 .items() 而不获取其中的默认字典值,但仍然使用魔术插值?

参考: http://docs.python.org/library/configparser.html

谢谢!

更新:有人指出这是预期的行为:默认值就像配置文件中的任何其他名称/值对一样。同样,配置文件中的名称/值对也可用于“神奇插值”,因此如果我定义:

foo: bar
zap: %(foo)snowl

我将得到 [... ('zap': 'barnowl')]

这非常简洁,但我仍然想知道是否可以完成我想要完成的任务:迭代配置文件中的名称/值对,使用变量插值,而不使用默认值。

我的具体场景是这样的:我想用 {basedir: '/foo/bar'} 之类的东西初始化配置对象,因为某些文件的绝对路径因安装而异。然后我需要将该配置对象传递给并让各种其他类迭代这些文件。我不希望每个读取配置的类都必须知道它是使用某些默认值初始化的,并且应该忽略它们,因为它们不是实际的文件。这可能吗?有什么方法可以隐藏 .item() 和 .get() 的默认值但仍然有插值?谢谢!

I'm using ConfigParser to load in data from a configuration file as follows:

test.conf:

[myfiles]
fileone: %(datadir)s/somefile.foo
filetwo: %(datadir)s/nudderfile.foo

load.py:

import ConfigParser

config = ConfigParser.ConfigParser({'datadir': '/tmp'})
config.read('test.conf')

print config.items('myfiles')
print config.get('myfiles', 'datadir')

Output:

$ python load.py 
[('datadir', '/tmp'), ('filetwo', '/tmp/nudderfile.foo'), ('fileone', '/tmp/somefile.foo')]
/tmp

I'm surprised that the defaults for variable substitution ('datadir', '/tmp') are showing up as part of the .items() and .get() returns, as if they were values in the configuration file. Is this behavior expected? Any work arounds, so that I can simply iterate .items() without getting the default dictionary values in there, but still using the magic interpolation?

Reference: http://docs.python.org/library/configparser.html

Thanks!

Update: It's been pointed out that this is the expected behavior: defaults are just like any other name/value pair in the configuration file. Similarly, the name/value pairs in the configuration file are also available for "magic interpolation", so if I define:

foo: bar
zap: %(foo)snowl

I'll get [... ('zap': 'barnowl')]

That's pretty neat, but I'm still wondering if I can accomplish what I want to accomplish: iterate over the name/value pairs in my configuration files, with interpolation of variables, without the defaults.

My specific scenario is this: I wanted to initialize the config object with something like {basedir: '/foo/bar'}, as the absolute paths to certain files varies by installation. Then I need to pass that config object around to and have various other classes iterate through the files. I don't want every class that reads the configuration to have to know that it was initialized with certain defaults and that it should ignore them, as they are not actual files. Is this possible? Any way to hide the defaults from .item() and .get() but still have interpolation? Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

大姐,你呐 2024-08-26 22:10:55

一般来说,我发现 configparser.Configparser 类非常有帮助,但也有所欠缺。 其他人也有

然而,它可以被子类化和扩展,有时很好,有时不太好(=非常依赖于实现)

这是您的问题的解决方案,在Python3中测试:

class ConfigParser(configparser.ConfigParser):
    """Can get options() without defaults
    """
    def options(self, section, no_defaults=False, **kwargs):
        if no_defaults:
            try:
                return list(self._sections[section].keys())
            except KeyError:
                raise NoSectionError(section)
        else:
            return super().options(section, **kwargs)

这是不好的例子之一,因为它正在部分复制 源代码 >选项()。如果 configparser 基类 RawConfigParser 能够提供一个包含异常转换的选项 _options(self,section) 的内部 getter,以及一个 options ,那就更好了() 会利用它。然后,在子类化中我们可以重用_options()

对于 Python 2,我相信唯一的变化是对 super(ConfigParser,self)super() 调用。

然后您可以使用:

print config.options('myfiles', no_defaults=True)

并使用该列表进行迭代。

Generally, I've found the configparser.Configparser class very helpful, but also lacking. Others have, too.

However, it can be subclassed and extended, sometimes nicely, sometimes not so nicely (=very implementation dependent)

Here's a solution for your problem, tested in Python3:

class ConfigParser(configparser.ConfigParser):
    """Can get options() without defaults
    """
    def options(self, section, no_defaults=False, **kwargs):
        if no_defaults:
            try:
                return list(self._sections[section].keys())
            except KeyError:
                raise NoSectionError(section)
        else:
            return super().options(section, **kwargs)

This is one of the bad examples, because it is partially copying the source code of options(). It would be nicer if the configparser base class RawConfigParser would provide an internal getter of options _options(self, section) which would incorporate the exception cast, and a options() which would make use of that. Then, in subclassing we could reuse the _options().

For Python 2, I believe the only change is the super() call to super(ConfigParser,self).

You can then use:

print config.options('myfiles', no_defaults=True)

And also use that list to iterate.

他不在意 2024-08-26 22:10:55

为了回答这个问题,我注册了一个帐户。当我搜索时,它似乎是谷歌上的热门搜索。

我深入研究了 源代码 >ConfigParser 找到我认为简单而有效的解决方案。

RawConfigParser 类(ConfigParser 继承)有一个名为 default_section 的关键字参数。我能够通过实例化来忽略配置的 DEFAULT 部分:

from configparser import ConfigParser

parser = ConfigParser(default_section=None)

我希望这也可以帮助其他人。

更新

实际上,default_section应该是一个字符串,您可以自定义默认部分的名称“DEFAULT”。

因此,您可以:

  1. 设置空字符串
  2. 将预期部分设置为默认部分
from configparser import ConfigParser

parser = ConfigParser(default_section="")
parser = ConfigParser(default_section="myfiles")

I’ve made an account for the express purpose of answering this question. It seemed to be a top hit on Google when I was searching.

I dug into the source of ConfigParser to find what I think is a simple and efficient solution.

There’s a keyword argument to the RawConfigParser class (which ConfigParser inherits) called default_section. I was able to ignore the DEFAULT section of my config by instantiating with:

from configparser import ConfigParser

parser = ConfigParser(default_section=None)

I hope this can help someone else as well.

Update

Actually, the default_section should be a string and you can customize the name of the default section which is 'DEFAULT'.

So either you can:

  1. Set empty string
  2. Set your expected section as the default one
from configparser import ConfigParser

parser = ConfigParser(default_section="")
parser = ConfigParser(default_section="myfiles")
你的呼吸 2024-08-26 22:10:55

你就不能过滤掉默认值吗?

例如:

filtered_items = [x for x in config.items('myfiles') if x[0] not in config.defaults()]

Can't you just filter out the defaults?

e.g.:

filtered_items = [x for x in config.items('myfiles') if x[0] not in config.defaults()]

说不完的你爱 2024-08-26 22:10:55

试试这个:

config = ConfigParser.ConfigParser({'blahblahblah': 'blah'})
config.read('test.conf')

blahblahblah 键也会出现在 items 中,不是因为它是 .ini 文件中的模板,而是因为您将其指定为默认值。这就是 ConfigParser 处理默认值的方式:如果它在文件中找不到它们,它会分配它们的默认值。

所以在我看来你在这里有一个简单的概念混淆。

Try this:

config = ConfigParser.ConfigParser({'blahblahblah': 'blah'})
config.read('test.conf')

The blahblahblah key will also appear in items, not because it's a template in the .ini file, but because you specified it as a default. This is how ConfigParser treats defaults: if it can't find them in the file, it assigns their default values.

So it appears to me you have a simple confusion of concepts here.

小耗子 2024-08-26 22:10:55

以下内容应仅提供 myfiles 部分中的键/值对,而不会列出 DEFAULT 中的键/值对:

list(set(config.items('myfiles'))-set(config.items('DEFAULT')))

The following should give you only the key/value pairs in the myfiles section without also listing out those in DEFAULT:

list(set(config.items('myfiles'))-set(config.items('DEFAULT')))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文