我正在尝试构建一个工具来从文本配置生成数据结构。我使用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}))
答案 0 :(得分:3)
从您的eval()
调用来看,您尝试实例化的类看起来就像您当前的全局范围。您可以自己查找它们并创建一个实例:
obj = globals()[txtobj]()
请注意,这将调用由txtobj
命名的任何全局对象,因此不应将此用于不受信任的数据。
创建自己允许的类字典可能更好:
classes = dict((c.__name__, c) for c in [Iteration,Observation,DataPoint])
# ...
obj = classes[txtobj]()