13.4 使用eval()完成更多的文字处理
配置文件中可能会包括一些类型的值,它们并没有简单的字符串表示。例如,集合可能会作为一个元组或list文本,一个映射可能会作为一个dict文本。我们有不同的选择来处理这些复杂的值。
这些选择围绕着一个问题,就是转换逻辑需要多复杂的Python语法。对于一些类型(int、float、bool、complex、decimal.Decimal和fractions.Fraction),可以安全地从字符串转换为一个一个文本值,因为这些类型对象的init()在处理字符串时不需要太多的Python语法。
然而,对于其他类型,字符串的转换就不是那么容易了,在处理上有以下几种选择。
- 禁止使用这些类型,使用配置文件的语法和处理规则,将非常简单的值组成复杂的Python对象。这很无聊但却是有效的。
- 使用ast.literal_eval()函数,因为它可以处理Python中文本值的许多情况。这通常是最理想的方案。
- 使用eval()直接执行字符串并创建所需要的Python对象。这种方式可以比ast.literal_eval()函数解析更多类型的对象。而这种级别广泛性是否真的必要?
使用ast模块来对结果对象进行编译和审查,审查过程会检查import语句和一些允许使用模块的小集合。它非常复杂,如果只是简单的则不做审查,或许应该定义一个框架而不是使用应用程序和配置文件。
对于使用RESTful的情况,将Python对象通过网络传输,使用eval()直接执行文本当然是不可信任的。参见第9章“序列化和保存——JSON、YAML、Pickle、CSV和XML”。
当读取本地的配置文件时,eval()是没用的。在一些情况下,Python代码的修改就像修改配置文件一样容易。当可以直接改代码时,eval()就不是那么有用了。
这里是使用ast.literal_eval()代替eval()的代码示例。
>>> import ast
>>> ast.literal_eval('(3,2)')
(3, 2)
以上代码放宽了配置文件中的值域。它虽然不支持所有对象,但是它支持大部分文本。
