简体   繁体   English

ConfigParser 中的列表

[英]Lists in ConfigParser

The typical ConfigParser generated file looks like:典型的 ConfigParser 生成的文件如下所示:

[Section]
bar=foo
[Section 2]
bar2= baz

Now, is there a way to index lists like, for instance:现在,有没有办法索引列表,例如:

[Section 3]
barList={
    item1,
    item2
}

Related question: Python's ConfigParser unique keys per section相关问题: Python's ConfigParser unique keys per section

Also a bit late, but maybe helpful for some.也有点晚了,但可能对某些人有帮助。 I am using a combination of ConfigParser and JSON:我正在使用 ConfigParser 和 JSON 的组合:

[Foo]
fibs: [1,1,2,3,5,8,13]

just read it with:只需阅读:

>>> json.loads(config.get("Foo","fibs"))
[1, 1, 2, 3, 5, 8, 13]

You can even break lines if your list is long (thanks @peter-smit):如果您的列表很长,您甚至可以断行(感谢@peter-smit):

[Bar]
files_to_check = [
     "/path/to/file1",
     "/path/to/file2",
     "/path/to/another file with space in the name"
     ]

Of course i could just use JSON, but i find config files much more readable, and the [DEFAULT] Section very handy.当然,我可以只使用 JSON,但我发现配置文件更具可读性,而且 [DEFAULT] 部分非常方便。

There is nothing stopping you from packing the list into a delimited string and then unpacking it once you get the string from the config.没有什么可以阻止您将列表打包成一个分隔的字符串,然后在从配置中获取字符串后将其解包。 If you did it this way your config section would look like:如果您这样做,您的配置部分将如下所示:

[Section 3]
barList=item1,item2

It's not pretty but it's functional for most simple lists.它不是很漂亮,但对于大多数简单的列表来说是有用的。

Coming late to this party, but I recently implemented this with a dedicated section in a config file for a list:来晚了,但我最近在配置文件中的一个专用部分实现了这个列表:

[paths]
path1           = /some/path/
path2           = /another/path/
...

and using config.items( "paths" ) to get an iterable list of path items, like so:并使用config.items( "paths" )获取路径项的可迭代列表,如下所示:

path_items = config.items( "paths" )
for key, path in path_items:
    #do something with path

Hope this helps other folk Googling this question ;)希望这有助于其他人在谷歌上搜索这个问题;)

One thing a lot of people don't know is that multi-line configuration-values are allowed.很多人不知道的一件事是允许多行配置值。 For example:例如:

;test.ini
[hello]
barlist = 
    item1
    item2

The value of config.get('hello','barlist') will now be: config.get('hello','barlist')现在是:

"\nitem1\nitem2"

Which you easily can split with the splitlines method (don't forget to filter empty items).您可以使用 splitlines 方法轻松拆分(不要忘记过滤空项目)。

If we look to a big framework like Pyramid they are using this technique:如果我们看看像 Pyramid 这样的大框架,他们正在使用这种技术:

def aslist_cronly(value):
    if isinstance(value, string_types):
        value = filter(None, [x.strip() for x in value.splitlines()])
    return list(value)

def aslist(value, flatten=True):
    """ Return a list of strings, separating the input based on newlines
    and, if flatten=True (the default), also split on spaces within
    each line."""
    values = aslist_cronly(value)
    if not flatten:
        return values
    result = []
    for value in values:
        subvalues = value.split()
        result.extend(subvalues)
    return result

Source 来源

Myself, I would maybe extend the ConfigParser if this is a common thing for you:我自己,如果这对您来说很常见,我可能会扩展 ConfigParser:

class MyConfigParser(ConfigParser):
    def getlist(self,section,option):
        value = self.get(section,option)
        return list(filter(None, (x.strip() for x in value.splitlines())))

    def getlistint(self,section,option):
        return [int(x) for x in self.getlist(section,option)]

Note that there are a few things to look out for when using this technique请注意,使用此技术时需要注意一些事项

  1. New lines that are items should start with whitespace (eg a space or a tab)作为项目的新行应以空格开头(例如空格或制表符)
  2. All following lines that start with whitespace are considered to be part of the previous item.以下所有以空格开头的行都被视为上一项的一部分。 Also if it has an = sign or if it starts with a ;此外,如果它有一个 = 符号或者它以 ; 开头。 following the whitespace.跟随空格。

If you want to literally pass in a list then you can use:如果你想从字面上传递一个列表,那么你可以使用:

ast.literal_eval()

For example configuration:例如配置:

[section]
option=["item1","item2","item3"]

The code is:代码是:

import ConfigParser
import ast

my_list = ast.literal_eval(config.get("section", "option"))
print(type(my_list))
print(my_list)

output:输出:

<type'list'>
["item1","item2","item3"]

No mention of the converters kwarg for ConfigParser() in any of these answers was rather disappointing.在这些答案中没有提到ConfigParser()converters kwarg是相当令人失望的。

According to the documentation you can pass a dictionary to ConfigParser that will add a get method for both the parser and section proxies.根据文档,您可以将字典传递给ConfigParser ,该字典将为解析器和部分代理添加一个get方法。 So for a list:所以对于一个列表:

example.ini例子.ini

[Germ]
germs: a,list,of,names, and,1,2, 3,numbers

Parser example:解析器示例:

cp = ConfigParser(converters={'list': lambda x: [i.strip() for i in x.split(',')]})
cp.read('example.ini')
cp.getlist('Germ', 'germs')
['a', 'list', 'of', 'names', 'and', '1', '2', '3', 'numbers']
cp['Germ'].getlist('germs')
['a', 'list', 'of', 'names', 'and', '1', '2', '3', 'numbers']

This is my personal favorite as no subclassing is necessary and I don't have to rely on an end user to perfectly write JSON or a list that can be interpreted by ast.literal_eval .这是我个人的最爱,因为不需要子类化,而且我不必依赖最终用户来完美地编写 JSON 或可由ast.literal_eval解释的ast.literal_eval

I landed here seeking to consume this...我降落在这里试图消耗这个......

[global]
spys = richard.sorge@cccp.gov, mata.hari@deutschland.gov

The answer is to split it on the comma and strip the spaces:答案是在逗号上拆分它并去除空格:

SPYS = [e.strip() for e in parser.get('global', 'spys').split(',')]

To get a list result:获取列表结果:

['richard.sorge@cccp.gov', 'mata.hari@deutschland.gov']

It may not answer the OP's question exactly but might be the simple answer some people are looking for.它可能无法准确回答 OP 的问题,但可能是某些人正在寻找的简单答案。

This is what I use for lists:这是我用于列表的内容:

config file content:配置文件内容:

[sect]
alist = a
        b
        c

code :代码 :

l = config.get('sect', 'alist').split('\n')

it work for strings它适用于字符串

in case of numbers在数字的情况下

config content:配置内容:

nlist = 1
        2
        3

code:代码:

nl = config.get('sect', 'alist').split('\n')
l = [int(nl) for x in nl]

thanks.谢谢。

I completed similar task in my project with section with keys without values:我在我的项目中完成了类似的任务,其中包含没有值的键:

import configparser

# allow_no_value param says that no value keys are ok
config = configparser.ConfigParser(allow_no_value=True)

# overwrite optionxform method for overriding default behaviour (I didn't want lowercased keys)
config.optionxform = lambda optionstr: optionstr

config.read('./app.config')

features = list(config['FEATURES'].keys())

print(features)

Output:输出:

['BIOtag', 'TextPosition', 'IsNoun', 'IsNomn']

app.config:应用程序配置:

[FEATURES]
BIOtag
TextPosition
IsNoun
IsNomn

So another way, which I prefer, is to just split the values, for example:所以我更喜欢的另一种方法是拆分值,例如:

#/path/to/config.cfg
[Numbers]
first_row = 1,2,4,8,12,24,36,48

Could be loaded like this into a list of strings or integers, as follows:可以像这样加载到字符串或整数列表中,如下所示:

import configparser

config = configparser.ConfigParser()
config.read('/path/to/config.cfg')

# Load into a list of strings
first_row_strings = config.get('Numbers', 'first_row').split(',')

# Load into a list of integers
first_row_integers = [int(x) for x in config.get('Numbers', 'first_row').split(',')]

This method prevents you from needing to wrap your values in brackets to load as JSON.此方法可防止您将值包装在方括号中以作为 JSON 加载。

Only primitive types are supported for serialization by config parser.配置解析器仅支持原始类型进行序列化。 I would use JSON or YAML for that kind of requirement.我会使用 JSON 或 YAML 来满足这种需求。

I faced the same problem in the past.我过去遇到过同样的问题。 If you need more complex lists, consider creating your own parser by inheriting from ConfigParser.如果您需要更复杂的列表,请考虑通过从 ConfigParser 继承来创建您自己的解析器。 Then you would overwrite the get method with that:然后你会用它覆盖 get 方法:

    def get(self, section, option):
    """ Get a parameter
    if the returning value is a list, convert string value to a python list"""
    value = SafeConfigParser.get(self, section, option)
    if (value[0] == "[") and (value[-1] == "]"):
        return eval(value)
    else:
        return value

With this solution you will also be able to define dictionaries in your config file.使用此解决方案,您还可以在配置文件中定义字典。

But be careful!但小心点! This is not as safe: this means anyone could run code through your config file.这并不安全:这意味着任何人都可以通过您的配置文件运行代码。 If security is not an issue in your project, I would consider using directly python classes as config files.如果您的项目中的安全性不是问题,我会考虑直接使用 python 类作为配置文件。 The following is much more powerful and expendable than a ConfigParser file:以下内容比 ConfigParser 文件更强大、更易消耗:

class Section
    bar = foo
class Section2
    bar2 = baz
class Section3
    barList=[ item1, item2 ]

If this is your config.ini:如果这是您的 config.ini:

[Section 3]
barList=item1,item2

Then with configparser you could do this:然后使用 configparser 你可以这样做:

from configparser import ConfigParser
config = ConfigParser()
config.read('config.ini')
my_list = config['Section 3']['barList'].split(',')

You will get:你会得到:

 my_list =  ['item1', 'item2']

The split()-method will return a list, see Python string docs. split() 方法将返回一个列表,请参阅 Python 字符串文档。

If you have white spaces in your config.ini like this:如果您的 config.ini 中有空格,如下所示:

[Section 3]
barList= item1, item2

Then you'd better do this:那你最好这样做:

my_list = [x.strip() for x in config['Section 3']['barList'].split(',')]

If your items are numbers (integers for instance), just apply:如果您的项目是数字(例如整数),只需应用:

my_list_of_ints = list(map(int, my_list))

You will get:你会得到:

my_list_of_ints =  [item1, item2]
import ConfigParser
import os

class Parser(object):
    """attributes may need additional manipulation"""
    def __init__(self, section):
        """section to retun all options on, formatted as an object
        transforms all comma-delimited options to lists
        comma-delimited lists with colons are transformed to dicts
        dicts will have values expressed as lists, no matter the length
        """
        c = ConfigParser.RawConfigParser()
        c.read(os.path.join(os.path.dirname(__file__), 'config.cfg'))

        self.section_name = section

        self.__dict__.update({k:v for k, v in c.items(section)})

        #transform all ',' into lists, all ':' into dicts
        for key, value in self.__dict__.items():
            if value.find(':') > 0:
                #dict
                vals = value.split(',')
                dicts = [{k:v} for k, v in [d.split(':') for d in vals]]
                merged = {}
                for d in dicts:
                    for k, v in d.items():
                        merged.setdefault(k, []).append(v)
                self.__dict__[key] = merged
            elif value.find(',') > 0:
                #list
                self.__dict__[key] = value.split(',')

So now my config.cfg file, which could look like this:所以现在我的config.cfg文件可能是这样的:

[server]
credentials=username:admin,password:$3<r3t
loggingdirs=/tmp/logs,~/logs,/var/lib/www/logs
timeoutwait=15

Can be parsed into fine-grained-enough objects for my small project.可以为我的小项目解析为足够细粒度的对象。

>>> import config
>>> my_server = config.Parser('server')
>>> my_server.credentials
{'username': ['admin'], 'password', ['$3<r3t']}
>>> my_server.loggingdirs:
['/tmp/logs', '~/logs', '/var/lib/www/logs']
>>> my_server.timeoutwait
'15'

This is for very quick parsing of simple configs, you lose all ability to fetch ints, bools, and other types of output without either transforming the object returned from Parser , or re-doing the parsing job accomplished by the Parser class elsewhere.这是为了非常快速地解析简单的配置,您将失去获取整数、布尔值和其他类型输出的所有能力,而无需转换从Parser返回的对象,或者重新执行由 Parser 类在其他地方完成的解析工作。

json.loads & ast.literal_eval seems to be working but simple list within config is treating each character as byte so returning even square bracket.... json.loads & ast.literal_eval似乎正在工作,但配置中的简单列表将每个字符视为字节,因此甚至返回方括号....

meaning if config has fieldvalue = [1,2,3,4,5]意思是如果配置有fieldvalue = [1,2,3,4,5]

then config.read(*.cfg) config['fieldValue'][0] returning [ in place of 1然后config.read(*.cfg) config['fieldValue'][0]返回[代替1

As mentioned by Peter Smit ( https://stackoverflow.com/a/11866695/7424596 ) You might want to extend ConfigParser, in addition, an Interpolator can be used to automatically convert into and from the list.正如 Peter Smit ( https://stackoverflow.com/a/11866695/7424596 ) 所提到的,您可能想要扩展 ConfigParser,此外,还可以使用 Interpolator 自动转换为列表和从列表中转换。

For reference at the bottom you can find code which automatically converts config like:作为参考,您可以在底部找到自动转换配置的代码,例如:

[DEFAULT]
keys = [
    Overall cost structure, Capacity, RAW MATERIALS,
    BY-PRODUCT CREDITS, UTILITIES, PLANT GATE COST,
    PROCESS DESCRIPTION, AT 50% CAPACITY, PRODUCTION COSTS,
    INVESTMENT, US$ MILLION, PRODUCTION COSTS, US ¢/LB,
    VARIABLE COSTS, PRODUCTION COSTS, MAINTENANCE MATERIALS
  ]

So if you request keys you will get:因此,如果您请求密钥,您将获得:

<class 'list'>: ['Overall cost structure', 'Capacity', 'RAW MATERIALS', 'BY-PRODUCT CREDITS', 'UTILITIES', 'PLANT GATE COST', 'PROCESS DESCRIPTION', 'AT 50% CAPACITY', 'PRODUCTION COSTS', 'INVESTMENT', 'US$ MILLION', 'PRODUCTION COSTS', 'US ¢/LB', 'VARIABLE COSTS', 'PRODUCTION COSTS', 'MAINTENANCE MATERIALS']

Code:代码:

class AdvancedInterpolator(Interpolation):
    def before_get(self, parser, section, option, value, defaults):
        is_list = re.search(parser.LIST_MATCHER, value)
        if is_list:
            return parser.getlist(section, option, raw=True)
        return value


class AdvancedConfigParser(ConfigParser):

    _DEFAULT_INTERPOLATION = AdvancedInterpolator()

    LIST_SPLITTER = '\s*,\s*'
    LIST_MATCHER = '^\[([\s\S]*)\]$'

    def _to_list(self, str):
        is_list = re.search(self.LIST_MATCHER, str)
        if is_list:
            return re.split(self.LIST_SPLITTER, is_list.group(1))
        else:
            return re.split(self.LIST_SPLITTER, str)


    def getlist(self, section, option, conv=lambda x:x.strip(), *, raw=False, vars=None,
                  fallback=_UNSET, **kwargs):
        return self._get_conv(
                section, option,
                lambda value: [conv(x) for x in self._to_list(value)],
                raw=raw,
                vars=vars,
                fallback=fallback,
                **kwargs
        )

    def getlistint(self, section, option, *, raw=False, vars=None,
            fallback=_UNSET, **kwargs):
        return self.getlist(section, option, int, raw=raw, vars=vars,
                fallback=fallback, **kwargs)

    def getlistfloat(self, section, option, *, raw=False, vars=None,
            fallback=_UNSET, **kwargs):
        return self.getlist(section, option, float, raw=raw, vars=vars,
                fallback=fallback, **kwargs)

    def getlistboolean(self, section, option, *, raw=False, vars=None,
            fallback=_UNSET, **kwargs):
        return self.getlist(section, option, self._convert_to_boolean,
                raw=raw, vars=vars, fallback=fallback, **kwargs)

Ps keep in mind importance of indentdation. Ps记住缩进的重要性。 As reads in ConfigParser doc string:正如在 ConfigParser 文档字符串中读取的那样:

Values can span multiple lines, as long as they are indented deeper than the first line of the value.值可以跨越多行,只要它们比值的第一行缩进得更深。 Depending on the parser's mode, blank lines may be treated as parts of multiline values or ignored.根据解析器的模式,空行可能被视为多行值的一部分或被忽略。

you can use list in config file then parse it in python您可以在配置文件中使用列表,然后在 python 中解析它

from ast import literal_eval

literal_eval("[1,2,3,4]")

import json

json.loads("[1,2,3,4]")

and also you can use json file behind your config file like this:您也可以在配置文件后面使用 json 文件,如下所示:

your config file :
[A]
json_dis = .example.jason
--------------------
your code :
import configparser
config = configparser.ConfigParser()
config.read('config.ini')
# getting items of section A
config.items('A')
# result is a list of key-values

To take Grr's answer (my favorite) a step further, instead of enclosing list items in quotes in the .ini file, you can use the map function.为了让 Grr 的答案(我最喜欢的)更进一步,您可以使用 map 函数,而不是在 .ini 文件中用引号将列表项括起来。 This allows you to pythonically specify list item datatypes.这允许您以 Python 方式指定列表项数据类型。

Config file:配置文件:

[section]
listKey1: 1001, 1002, 1003
listKey2: AAAA, BBBB, CCCC

Code:代码:

cfgFile = 'config.ini'
parser = ConfigParser(converters={'list': lambda x: [i.strip() for i in x.split(',')]})
parser.read(cfgFile)

list1 = list(map(int, parser.getlist('section', 'listKey1')))
list2 = list(map(str, parser.getlist('section', 'listKey2')))

print(list1)
print(list2)

Output:输出:

[1001, 1002, 1003]
['AAAA', 'BBBB', 'CCCC']

An improvement on split(',') might be to treat the comma separated values as a record in a CSV file对 split(',') 的改进可能是将逗号分隔值视为 CSV 文件中的记录

import csv
my_list = list(csv.reader([config['Section 3']['barList']], dialect=csv.excel))[0]

You can configure a dialect to parse whatever style of CSV you like.您可以配置方言来解析您喜欢的任何 CSV 样式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM