从没有eval()的解析文本生成python数据结构

时间:2011-04-11 18:04:21

标签: python

我正在尝试构建一个工具来从文本配置生成数据结构。我使用pyparsing来解析命令......

配置文件:

add Iteration name = "Cisco 10M/half"
    append Observation name = "packet loss"
        assign Observation results_text = 0.0
        assign Observation results_bool = True
        append DataPoint
            assign DataPoint metric = txpackets
            assign DataPoint units = packets

PYPARSING COMMANDS

['add', 'Iteration', ['name', 'Cisco 10M/half']]
['append', 'Observation', ['name', 'packet loss']]
['assign', 'Observation', ['results_text', '0']]
['assign', 'Observation', ['results_bool', 'True']]
['append', 'DataPoint']
['assign', 'DataPoint', ['metric', 'txpackets']]
['assign', 'DataPoint', ['units', 'packets']]

第一列是命令动词,第二列是我已定义的类的名称。

目前,我能够提出的唯一解决方案是构建结果数据结构,如下所示:

if cmd == 'add':
    obj = eval('%s()' % (txtobj))  # Create the TestData object

对于第一个命令,它需要调用Iteration(),这是我导入解析器的类的名称。

有没有办法从文本配置构建类而不诉诸eval()?如果是这样,你会怎么做?

修改

Sven的回答假设我已经创建了类,但动态创建类实际上是问题的一部分。

这就是我如何动态创建一个名为'Child'的新类,假设一个名为Parent的父类已经在我的代码中......

>>> child_name = "Child"
>>> child_parents = (Parent,)
>>> child body = """
def __init__(self, arg1):
    # Initialization for the Child class
    self.foo = do_something(arg1)
"""
>>> child_dict = {}
>>> exec(child_body, globals(), child_dict)
>>> childobj = type(child_name, child_parents, child_dict)
>>> childobj.__name__
'Child'
>>> childobj.__bases__
(<type 'object'>,)
>>> # Instantiating the new Child object...
>>> childinst = childobj()
>>> childinst
<__main__.Child object at 0x1c91710>
>>>

如果我需要动态创建全局或局部变量,我应该避免使用globals()并使用dict() ...

>>> vars = {}
>>> varname = 'foo'
>>> vars[varname] = True
>>> 

在评论中,我还问过如何为方法调用生成动态关键字... 如:

eval('log.append(%s._replace(%s = val))' % (objtxt, key)

解决方案是对类实例使用Sven的答案(下面),并在方法args中使用mapping(即dict)...

classes = dict((c.__name__, c) for c in [Iteration,Observation,DataPoint])
# ...
obj = classes[txtobj]()
log.append(obj._replace(**{"%s" % key: val}))

1 个答案:

答案 0 :(得分:3)

从您的eval()调用来看,您尝试实例化的类看起来就像您当前的全局范围。您可以自己查找它们并创建一个实例:

obj = globals()[txtobj]()

请注意,这将调用由txtobj命名的任何全局对象,因此不应将此用于不受信任的数据。

创建自己允许的类字典可能更好:

classes = dict((c.__name__, c) for c in [Iteration,Observation,DataPoint])
# ...
obj = classes[txtobj]()