如何比较两个Python AST,忽略参数?

huangapple go评论59阅读模式
英文:

How to compare two Python ASTs, ignoring arguments?

问题

我想要优雅地比较两个Python表达式,忽略参数中的任何差异。例如,比较plt.show()plt.show(*some-args)应该返回True

我尝试使用ast解析表达式,如下所示:

import ast

node1 = ast.parse("plt.show()").body[0]
node2 = ast.parse("plt.show(*some-args)").body[0]
print(node1 == node2)

返回:False

英文:

I want to elegantly compare two Python expressions ignoring any differences in the arguments. For example comparing plt.show() and plt.show(*some-args) should return True.

I've tried parsing the expressions using ast as follows:

import ast

node1 = ast.parse("plt.show()").body[0]
node2 = ast.parse("plt.show(*some-args)").body[0]
print(node1 == node2)

Returns: False

答案1

得分: 0

from itertools import zip_longest
from typing import Union

def compare_ast(node1: Union[ast.expr, list[ast.expr]], node2: Union[ast.expr, list[ast.expr]], ignore_args=False) -> bool:
    """比较两个 AST 节点是否相等。"""
    if type(node1) is not type(node2):
        return False

    if isinstance(node1, ast.AST):
        for k, v in vars(node1).items():
            if k in {"lineno", "end_lineno", "col_offset", "end_col_offset", "ctx"}:
                continue
            if ignore_args and k == "args":
                continue
            if not compare_ast(v, getattr(node2, k), ignore_args):
                return False
        return True

    elif isinstance(node1, list) and isinstance(node2, list):
        return all(compare_ast(n1, n2, ignore_args) for n1, n2 in zip_longest(node1, node2))
    else:
        return node1 == node2
import ast

node1 = ast.parse("plt.show()").body[0]
node2 = ast.parse("plt.show(*some-args)").body[0]
print(compare_ast(node1, node2, ignore_args=True))

Returns: True


<details>
<summary>英文:</summary>

Some slight modifications to [@Seanny123&#39;s answer](https://stackoverflow.com/a/66733795/11080806):
```python
from itertools import zip_longest
from typing import Union


def compare_ast(node1: Union[ast.expr, list[ast.expr]], node2: Union[ast.expr, list[ast.expr]], ignore_args=False) -&gt; bool:
    &quot;&quot;&quot;Compare two AST nodes for equality.&quot;&quot;&quot;
    if type(node1) is not type(node2):
        return False

    if isinstance(node1, ast.AST):
        for k, v in vars(node1).items():
            if k in {&quot;lineno&quot;, &quot;end_lineno&quot;, &quot;col_offset&quot;, &quot;end_col_offset&quot;, &quot;ctx&quot;}:
                continue
            if ignore_args and k == &quot;args&quot;:
                continue
            if not compare_ast(v, getattr(node2, k), ignore_args):
                return False
        return True

    elif isinstance(node1, list) and isinstance(node2, list):
        return all(compare_ast(n1, n2, ignore_args) for n1, n2 in zip_longest(node1, node2))
    else:
        return node1 == node2

Example:

import ast

node1 = ast.parse(&quot;plt.show()&quot;).body[0]
node2 = ast.parse(&quot;plt.show(*some-args)&quot;).body[0]
print(compare_ast(node1, node2, ignore_args=True))

Returns: True

huangapple
  • 本文由 发表于 2023年5月28日 23:23:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/76352198.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定