ConfigParser 中的列表

发布于 2024-07-09 03:15:17 字数 348 浏览 12 评论 0原文

典型的 ConfigParser 生成的文件如下所示:

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

现在,有没有一种方法可以索引列表,例如:

[Section 3]
barList={
    item1,
    item2
}

相关问题: Python 的 ConfigParser 每个部分的唯一键

The typical ConfigParser generated file looks like:

[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

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

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

发布评论

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

评论(20

女皇必胜 2024-07-16 03:15:18

如果你想字面上传递一个列表,那么你可以使用:

ast.literal_eval()

例如配置:

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

代码是:

import ConfigParser
import ast

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

输出:

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

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"]
樱花坊 2024-07-16 03:15:18

我登陆这里寻求消耗这个...

[global]
spys = [email protected], [email protected]

答案是将其拆分为逗号并去掉空格:

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

要获得列表结果:

['[email protected]', '[email protected]']

它可能无法准确回答OP的问题,但可能是一些人正在寻找的简单答案。

I landed here seeking to consume this...

[global]
spys = [email protected], [email protected]

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:

['[email protected]', '[email protected]']

It may not answer the OP's question exactly but might be the simple answer some people are looking for.

独自←快乐 2024-07-16 03:15:18

这就是我用于列表的内容:

配置文件内容:

[sect]
alist = a
        b
        c

代码:

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

配置内容的字符串

它适用于数字

nlist = 1
        2
        3

代码:

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

谢谢。

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.

夏花。依旧 2024-07-16 03:15:18

因此,我更喜欢的另一种方法是仅拆分值,例如:

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

可以像这样加载到字符串或整数列表中,如下所示:

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(',')]

此方法可以防止您需要将值括在括号中以作为 JSON 加载。

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.

强者自强 2024-07-16 03:15:18

我在项目中完成了类似的任务,其中包含没有值的键的部分:

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)

输出:

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

app.config:

[FEATURES]
BIOtag
TextPosition
IsNoun
IsNomn

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
怕倦 2024-07-16 03:15:18

配置解析器仅支持原始类型进行序列化。 我会使用 JSON 或 YAML 来满足这种要求。

Only primitive types are supported for serialization by config parser. I would use JSON or YAML for that kind of requirement.

相对绾红妆 2024-07-16 03:15:18

要进一步采用 Grr 的答案(我最喜欢的),您可以使用 map 函数,而不是在 .ini 文件中将列表项括在引号中。 这允许您以Python方式指定列表项数据类型。

配置文件:

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

代码:

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)

输出:

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

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. This allows you to pythonically specify list item datatypes.

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']
初心 2024-07-16 03:15:18

如果这是您的 config.ini:

[Section 3]
barList=item1,item2

那么使用 configparser 您可以执行以下操作:

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

您将得到:

 my_list =  ['item1', 'item2']

split() 方法将返回一个列表,请参阅 Python 字符串文档。

如果您的文件中有空格config.ini 像这样:

[Section 3]
barList= item1, item2

那么你最好这样做:

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

如果你的项目是数字(例如整数),只需应用:

my_list_of_ints = list(map(int, my_list))

你将得到:

my_list_of_ints =  [item1, item2]

If this is your config.ini:

[Section 3]
barList=item1,item2

Then with configparser you could do this:

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.

If you have white spaces in your config.ini like this:

[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]
春庭雪 2024-07-16 03:15:18

我过去也遇到过同样的问题。 如果您需要更复杂的列表,请考虑通过继承 ConfigParser 创建您自己的解析器。 然后你可以用以下方法覆盖 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

使用此解决方案,你还可以在配置文件中定义字典。

不过要小心! 这不太安全:这意味着任何人都可以通过您的配置文件运行代码。 如果您的项目中安全性不是问题,我会考虑直接使用 python 类作为配置文件。 以下内容比 ConfigParser 文件更强大且可消耗:

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

I faced the same problem in the past. If you need more complex lists, consider creating your own parser by inheriting from ConfigParser. Then you would overwrite the get method with that:

    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. The following is much more powerful and expendable than a ConfigParser file:

class Section
    bar = foo
class Section2
    bar2 = baz
class Section3
    barList=[ item1, item2 ]
鹿港小镇 2024-07-16 03:15:18
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(',')

现在我的 config.cfg 文件可能如下所示:

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

可以为我的小项目解析为足够细粒度的对象。

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

这是为了非常快速地解析简单的配置,您将失去获取整数、布尔值和其他类型输出的所有能力,而无需转换从解析器返回的对象,或重新执行由其他地方的 Parser 类。

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:

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

装迷糊 2024-07-16 03:15:18

json.loads & ast.literal_eval 似乎有效,但配置中的简单列表将每个字符视为字节,因此返回甚至方括号....

意味着如果配置有 fieldvalue = [1,2,3, 4,5]

然后config.read(*.cfg)
config['fieldValue'][0] 返回 [ 代替 1

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

meaning if config has fieldvalue = [1,2,3,4,5]

then config.read(*.cfg)
config['fieldValue'][0] returning [ in place of 1

〗斷ホ乔殘χμё〖 2024-07-16 03:15:18

正如彼得·斯密特(https://stackoverflow.com/a/11866695/7424596)所述
您可能想要扩展 ConfigParser,此外,还可以使用 Interpolator 自动在列表之间进行转换。

作为参考,您可以在底部找到自动转换配置的代码,例如:

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

因此,如果您请求密钥,您将得到:

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

代码:

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]*)\]

Ps请记住缩进的重要性。 正如 ConfigParser 文档字符串中所读:

<块引用>

值可以跨越多行,只要缩进得更深
比第一行的值。 根据解析器的模式,空白
行可以被视为多行值的一部分或被忽略。

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请记住缩进的重要性。 正如 ConfigParser 文档字符串中所读:

<块引用>

值可以跨越多行,只要缩进得更深
比第一行的值。 根据解析器的模式,空白
行可以被视为多行值的一部分或被忽略。

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.

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]*)\]

Ps keep in mind importance of indentdation. As reads in ConfigParser doc string:

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.

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. As reads in ConfigParser doc string:

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.

谎言月老 2024-07-16 03:15:18

您可以在配置文件中使用列表,然后在 python 中解析它

from ast import literal_eval

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

import json

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

,也可以在配置文件后面使用 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

you can use list in config file then parse it in 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:

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
和影子一齐双人舞 2024-07-16 03:15:18

split(',') 的改进可能是将逗号分隔值视为 CSV 文件中的记录。

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

您可以配置方言来解析您喜欢的任何样式的 CSV。

An improvement on split(',') might be to treat the comma separated values as a record in a CSV file

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.

明媚殇 2024-07-16 03:15:18

[项目]
list = 1,2,3

获取使用:

nums = config.get('items', 'list')
nums_list = nums.split(",")
print(nums_list)

结果应该是:[1,2,3]

[items]
list = 1,2,3

get using:

nums = config.get('items', 'list')
nums_list = nums.split(",")
print(nums_list)

Result should be: [1,2,3]

烙印 2024-07-16 03:15:17

我正在使用 ConfigParser 和 JSON 的组合:

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

只需阅读它:

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

如果您的列表很长,您甚至可以换行(感谢@peter-smit):

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

当然我可以只使用 JSON,但我发现配置文件更具可读性, [DEFAULT] 部分非常方便。

I am using a combination of ConfigParser and 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):

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

翻身的咸鱼 2024-07-16 03:15:17

没有什么可以阻止您将列表打包到分隔字符串中,然后在从配置中获取字符串后将其解包。 如果您这样做,您的配置部分将如下所示:

[Section 3]
barList=item1,item2

它并不漂亮,但对于大多数简单的列表来说它是有效的。

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.

娇纵 2024-07-16 03:15:17

我最近使用列表的配置文件中的专用部分实现了此功能:

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

并使用 config.items( "paths" ) 来获取路径项的可迭代列表,如下所示:

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

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:

path_items = config.items( "paths" )
for key, path in path_items:
    #do something with path
Saygoodbye 2024-07-16 03:15:17

很多人不知道的一件事是允许多行配置值。 例如:

;test.ini
[hello]
barlist = 
    item1
    item2

config.get('hello','barlist') 的值现在将是:

"\nitem1\nitem2"

您可以使用 splitlines 方法轻松分割它(不要忘记过滤空项目)。

如果我们寻找像 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

来源

我自己,如果这对您来说是常见的事情,我可能会扩展 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)]

请注意,使用此技术时需要注意一些事项

  1. 作为项目的新行应以空格(例如空格或制表符)开头
  2. 所有以下以空格开头的行被视为前一项的一部分。 另外,如果它有 = 符号或者以 ; 开头 跟随空白。

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:

"\nitem1\nitem2"

Which you easily can split with the splitlines method (don't forget to filter empty items).

If we look to a big framework like Pyramid they are using this technique:

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:

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 (e.g. 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.
堇年纸鸢 2024-07-16 03:15:17

没有提及 转换器 kwarg < code>ConfigParser() 在这些答案中的任何一个都相当令人失望。

根据文档,您可以将字典传递给 ConfigParser,这将为解析器和节代理添加一个 get 方法。 因此,对于列表:

example.ini

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

解析器示例:

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

这是我个人最喜欢的,因为不需要子类化,并且我不必依赖最终用户完美地编写 JSON 或可以由 ast 解释的列表。文字评估。

No mention of the converters kwarg for ConfigParser() in any of these answers was rather disappointing.

According to the documentation you can pass a dictionary to ConfigParser that will add a get method for both the parser and section proxies. So for a list:

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

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