Python: How to create a dictionary from properties file while omitting comments

拈花ヽ惹草 提交于 2020-05-25 17:20:17

问题


I've searched for the answer to this here for awhile and haven't found it, so hope this isn't a dupe.

I have a properties file that mostly contains key=value pairs, but also contains #comments. I need to put it in a dictionary so I can grab values at will. In a file without #comments, the following works perfectly.

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

But not so when there are comments present. If there's #comment present, dictionary says

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

I've tried wrapping the dictionary creation in conditionals with

if not line.startswith('#'):

But I can't seem to get that to work. Suggestions? Thanks!


回答1:


To address your newest constraint about blank lines, I would try something like:

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

It's very clear and it's easy to add on extra constraints, whereas using a dict comprehension will get quite bloated. However, you could always format it nicely

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:


You should just use the built-in configparser which is made to read ini-style configuration files. It allows comments using ; and # by default, so it should work for you.

For .properties files you might need to trick a bit as the configparser generally expects section names. You can do this easily by adding a dummy section while reading it though:

>>> 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

(Using the same example file as mtitan8)

For Python 2, use from ConfigParser import ConfigParser instead.




回答3:


Given a properties file test.txt as you've described:

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

You can do the following:

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

This seems just like the code you said you tried using if not line.startswith('#'), so hopefully this working example will help you pinpoint the bug.




回答4:


Why force this into one line? Two weeks from now a user will put a space somewhere, or want to use quotes and you have to go unwind the code. Just make a function now which handles the input and be done with it. It also means you can use unit tests to ensure it works and stays working.

Given this input:

foo=bar
#skip me

bar=baz
baz=foo

#skip me too!

The following code will handle it all nicely.

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

BTW, I like poke's suggestion of using ConfigParser. But the hack of adding a section may or may not work for everyone.

If you want to move the comment checking into the parse_line() function you could return None, None and check for that before putting the key/value pair into the dictionary.




回答5:


shouldn't line.startswith('#') better read line.strip().startswith('#')?

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


来源:https://stackoverflow.com/questions/19799522/python-how-to-create-a-dictionary-from-properties-file-while-omitting-comments

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!