将ConfigParser值转换为Python数据类型

17 投票
6 回答
12020 浏览
提问于 2025-04-16 18:48

ConfigParser 这个工具要求所有的部分、键和数值都必须是字符串,这一点并不奇怪。它有一些方法可以把这些字符串转换成其他数据类型,比如 getfloat 用来获取浮点数,getint 用来获取整数,getboolean 用来获取布尔值。如果你不知道数据的类型,可以用 eval()get() 包裹起来,这样就可以把字符串进行评估,比如:

>>> from ConfigParser import SafeConfigParser
>>> cp = SafeConfigParser()
>>> cp.add_section('one')
>>> cp.set('one', 'key', '42')
>>> print cp.get('one', 'key')
'42'
>>> print eval(cp.get('one', 'key'))
42
>>> cp.set('one', 'key', 'None')
>>> print eval(cp.get('one', 'key'))
None
>>> 

有没有更好的方法呢?我想这可能会有一些严重的安全隐患,因为从文件中评估文本是有风险的——我承认这一点;不过我完全信任这个文件。

我本来想用 pickle 来处理这个,但我真的希望配置文件能让人看得懂。

你会怎么做呢?

6 个回答

5

这里还有另一个解决方案。你可以创建一个 getany() 方法,它会自动识别并返回大多数数据类型的正确类型,包括 str(字符串)、int(整数)、float(浮点数)、bool(布尔值)和 None(空值)。

需要注意的是,配置文件中的表示法必须是Python格式,这样才能正常工作。例如,布尔值的真要写成 True,空值要写成 None

from ast import literal_eval
import configparser

parser = configparser.ConfigParser(converters={"any": lambda x: literal_eval(x)})
value = parser.getany("section", "key")
# ...
5

如果你在寻找一个更简单的解决办法,而不是自己去转换数据类型,你可以使用 localconfig 这个模块,它会帮你自动转换。这个转换是通过根据值来猜测数据类型来完成的(比如,123 是整数,123.4 是浮点数,true 是布尔值,等等)。

下面是一个跟提问者的例子类似的示例:

>>> from localconfig import config
>>> config.read('[one]\nkey = 42\nkey2 = None')
>>> config.one.key, type(config.one.key)
(42, <type 'int'>)
>>> config.one.key2, type(config.one.key2)
(None, <type 'NoneType'>)
>>> config.get('one', 'key'), config.get('one', 'key2')
(42, None)

这个模块是基于 ConfigParser 的,所以它完全兼容。

你可以在这里查看它: https://pypi.python.org/pypi/localconfig

16

如果你使用的是Python 2.6或更高版本,可以使用ast.literal_eval这个功能:

ast.literal_eval(node_or_string)
这个功能可以安全地评估一个表达式节点或者一个包含Python表达式的字符串。你提供的字符串或节点只能包含以下几种Python的基本数据结构:字符串、数字、元组、列表、字典、布尔值和None。

这个功能可以用来安全地评估来自不可信来源的包含Python表达式的字符串,而不需要自己去解析这些值。

当字符串是安全的时,它的工作方式和eval是一样的:

>>> literal_eval("{'key': 10}")
{'key': 10}

但是如果出现文档中没有列出的其他类型,它就会失败:

>>> literal_eval("import os; os.system('rm -rf somepath')")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib64/python2.6/ast.py", line 49, in literal_eval
    node_or_string = parse(node_or_string, mode='eval')
  File "/usr/lib64/python2.6/ast.py", line 37, in parse
    return compile(expr, filename, mode, PyCF_ONLY_AST)
  File "<unknown>", line 1
    import os; os.system('rm -rf somepath')
         ^
SyntaxError: invalid syntax

撰写回答