在python中使用ast从字符串表达式中对变量名进行排序时出错



我需要解析这个方程列表,并将其分为两个列表,如代码中所示,它们出现的顺序很重要,然而,一旦解析完毕,变量列表var1的顺序就不像方程中那样正确了,有什么暗示吗?

eq_list2 = ["der_w_hSP - w_FW + 2*t_FW", "2*der_t_CP - R_CI + R_CO", "3*der_w_BSS - w_FW + 4*s_CI + 2*s_BRC + 3*t_BW + 2*t_CW"]
var2 = []
var1 = []
for i in range(len(eq_list2)):
#print(eq_list[i])
names2 = [
node.id for node in ast.walk(ast.parse(eq_list2[i]))
if isinstance(node, ast.Name)
]
print(names2)
for k in range(len(names2)):
if names2[k].startswith('der_'):
print('yes')
var2.append(names2[k])
else:
print('false')
var1.append(names2[k])
print(var2)
print(var1)
['der_w_hSP', 'der_t_CP', 'der_w_BSS']
['w_FW', 't_FW', 'R_CO', 'R_CI', 't_CW', 't_BW', 's_BRC', 'w_FW', 's_CI']

ast.walk被记录为生成树的节点">没有指定的顺序";,这很容易通过检查代码来验证(您可以在机器上Python库目录中的文件ast.py中找到(:

def walk(node):
"""
Recursively yield all descendant nodes in the tree starting at *node*
(including *node* itself), in no specified order.  This is useful if you
only want to modify nodes in place and don't care about the context.
"""
from collections import deque
todo = deque([node])
while todo:
node = todo.popleft()
todo.extend(iter_child_nodes(node))
yield node

该代码使用双端队列来存储未访问的AST节点,以避免递归。实际上,这是广度优先遍历,这意味着将首先访问更靠近树根的节点。由于表达式大多是左关联的,因此右运算符往往更接近解析树的根,因此在访问顺序中出现得更早。

按照从左到右的顺序访问节点的一种简单方法是使用递归遍历器:

def dfswalk(node):
"""
Recursively yield all descendant nodes of an AST starting at *node*
(including *node* itself) in depth-first order.
"""
yield node
for child in ast.iter_child_nodes(node):
yield from dfswalk(child)

使用该函数而不是ast.walk应该按照您期望的顺序生成变量,尽管我不认为iter_child_nodes可以保证按从左到右的文本顺序迭代每个节点类型,所以您需要针对您感兴趣的各种语法对其进行测试。

如果您预计必须处理非常复杂的表达式,您可以使用自己的堆栈而不是递归。

最新更新