Python:如何在省略注释的同时从属性文件创建字典

Posted

技术标签:

【中文标题】Python:如何在省略注释的同时从属性文件创建字典【英文标题】:Python: How to create a dictionary from properties file while omitting comments 【发布时间】:2013-11-16 22:46:10 【问题描述】:

我已经在这里搜索了一段时间的答案,但还没有找到,所以希望这不是一个骗局。

我有一个属性文件,其中大部分包含键=值对,但也包含#cmets。我需要把它放在字典里,这样我就可以随意获取值了。在没有#cmets 的文件中,以下内容完美运行。

myprops = dict(line.strip().split('=') for line in open('/Path/filename.properties'))
print myprops['key']

但当有 cmets 存在时,情况并非如此。如果存在#comment,字典会说

"ValueError: dictionary update sequence element #x has length 1, 2 is required"

我已经尝试将字典创建包装在条件句中

if not line.startswith('#'):

但我似乎无法让它发挥作用。建议?谢谢!

【问题讨论】:

所以说清楚,你试过dict(line.strip().split('=') for line in open('/Path/filename.properties') if not line.startswith('#'))? 我没有这样尝试过,但确实有效。谢谢! 我可能说得太早了。我认为错误只是由于注释行引起的。也有空行。它给出了同样的错误。我以为line.strip() 会跳过所有的空白行。 【参考方案1】:

为了解决您对空白行的最新限制,我会尝试以下方法:

myprops = 
with open('filename.properties', 'r') as f:
    for line in f:
        line = line.rstrip() #removes trailing whitespace and '\n' chars

        if "=" not in line: continue #skips blanks and comments w/o =
        if line.startswith("#"): continue #skips comments which contain =

        k, v = line.split("=", 1)
        myprops[k] = v

它非常清晰,并且很容易添加额外的约束,而使用 dict 推导式会变得非常臃肿。但是,您总是可以很好地格式化它

myprops = dict(line.strip().split('=') 
               for line in open('/Path/filename.properties'))
               if ("=" in line and 
                   not line.startswith("#") and
                   <extra constraint> and
                   <another extra constraint>))

【讨论】:

【参考方案2】:

您应该只使用内置的 configparser 来读取 ini 样式的配置文件。它允许 cmets 默认使用 ;#,所以它应该适合你。

对于.properties 文件,您可能需要进行一些技巧,因为 configparser 通常需要部分名称。您可以通过在阅读时添加一个虚拟部分来轻松做到这一点:

>>> from configparser import ConfigParser
>>> config = ConfigParser()
>>> with open(r'C:\Users\poke\Desktop\test.properties') as f:
        config.read_string('[config]\n' + f.read())

>>> for k, v in config['config'].items():
        print(k, v)

foo bar
bar baz
baz foo

(使用与 mtitan8 相同的示例文件)

对于 Python 2,请改用 from ConfigParser import ConfigParser

【讨论】:

这很酷。谢谢。我的属性文件不是带有括号部分名称(如“[config]”)的 windows 样式。没有这些,ConfigParser 可以工作吗?谢谢! 是的,这基本上就是我在示例代码中这样做的原因。我的test.properties 也没有任何section,所以在读取文件时,我只是在文件顶部添加了一个dummy section,这样configparser就不会抱怨了。 我必须做import ConfigParserfrom configparser import ConfigParser 给我一个导入错误。不过,无论如何,我在下一行config = ConfigParser() 上收到一个错误,指出“模块”对象不可调用。如果它对这个解决方案有影响,我在 Python 2.7 上。谢谢。 对,你需要在 Python 2 中使用 from ConfigParser import ConfigParser,因为那时模块名称还没有在 lowercase 中。 如果您的属性文件包含相同的属性但大小写不同,上述方法将不起作用。例如一个属性是foo=bar,而另一个属性是Foo=bar。你会得到一个错误option 'foo' in section 'config' already exists【参考方案3】:

给定一个属性文件 test.txt,正如你所描述的:

foo=bar
#skip me
bar=baz
baz=foo
#skip me too!

您可以执行以下操作:

>>> D = dict( l.rstrip().split('=') for l in open("test.txt")
              if not l.startswith("#") )
>>> D
'baz': 'foo', 'foo': 'bar', 'bar': 'baz'

这看起来就像你说你尝试使用 if not line.startswith('#') 的代码,所以希望这个工作示例能帮助你查明错误。

【讨论】:

【参考方案4】:

为什么要把它强行写成一行?两周后,用户将在某处放置一个空格,或者想要使用引号,而您必须展开代码。现在只需创建一个函数来处理输入并完成它。这也意味着您可以使用单元测试来确保它正常工作并继续工作。

鉴于此输入:

foo=bar
#skip me

bar=baz
baz=foo

#skip me too!

下面的代码可以很好地处理这一切。

import sys

def parse_line(input):
    key, value = input.split('=')
    key = key.strip()  # handles key = value as well as key=value
    value = value.strip()

    return key, value

if __name__ == '__main__':
    data = 

    with open(sys.argv[1]) as fp:
        for line in fp:
            line = line.strip()
            if not line or line.startswith('#'):
                continue

            key, value = parse_line(input)
            data[key] = value

    print data

顺便说一句,我喜欢 poke 关于使用 ConfigParser 的建议。但是添加一个部分的技巧可能对每个人都有效,也可能不适用。

如果您想将注释检查移到 parse_line() 函数中,您可以返回 None、None 并在将键/值对放入字典之前进行检查。

【讨论】:

【参考方案5】:

line.startswith('#') 不应该更好地阅读line.strip().startswith('#')

dict(line.strip().split('=') for line in open('/Path/filename.properties') 
                             if not line.strip().startswith('#'))

【讨论】:

这没有提供问题的答案。要批评或要求作者澄清,请在他们的帖子下方发表评论 - 您可以随时评论自己的帖子,一旦您有足够的reputation,您就可以comment on any post。 对,我试图改进答案,但不允许我添加评论,所以我宁愿按照允许的方式而不是不允许的方式。【参考方案6】:

没有一个解决方案考虑到该值可以包含= 符号。

想象以下文件:

baz=foo
foo="foo=bar"
bar=baz

因此,我建议使用以下代码:

>>> D = dict( l.rstrip().split('=', maxsplit=1) for l in open("test.txt") if not l.startswith("#") )
>>> D
'baz': 'foo', 'foo': '"foo=bar"', 'bar': 'baz'

【讨论】:

以上是关于Python:如何在省略注释的同时从属性文件创建字典的主要内容,如果未能解决你的问题,请参考以下文章

如何从接口中省略一个属性,而不是 TypeScript 中的类型?

KEIL如何查看有效代码长度 省略注释

Python3 基础语法:编码标识符python保留字注释多行语句等介绍

如何禁用警告“省略局部变量的类型注释”?在 Dart 中(带有 Pedantic 包)

python面向对象

CSS显示两行或三行文字,然后多出的部分省略号代替