ast.fix_missing_locations 什么时候改变树?
When does ast.fix_missing_locations change the tree?
我试图找到一个示例,其中 NodeTransformer
继承人的 visit
与 NodeTransformer
继承人的 visit
不同 并且 在树上使用 fix_missing_locations
。
这是来自 documentation 的示例(由于某些原因它不起作用,即树不会改变,这取决于我们是否应用 fix_missing_locations
):
from ast import *
class RewriteName(NodeTransformer):
def visit_Name(self, node):
return Subscript(
value=Name(id='data', ctx=Load()),
slice=Constant(value=node.id),
ctx=node.ctx
)
tree = parse('foo', mode='eval')
new_tree = fix_missing_locations(RewriteName().visit(tree))
new_uncorrected_tree = RewriteName().visit(tree)
new_tree_str = dump(new_tree, include_attributes=True)
new_uncorrected_tree_str = dump(new_uncorrected_tree, include_attributes=True)
print(new_tree_str == new_uncorrected_tree_str) # True
以上代码问题如下:
...
tree = parse('foo', mode='eval')
new_uncorrected_tree = RewriteName().visit(tree)
new_uncorrected_tree2 = RewriteName().visit(tree)
new_tree = fix_missing_locations(new_uncorrected_tree2)
print(
tree is new_uncorrected_tree, # True
tree is new_uncorrected_tree2, # True
tree is new_tree) # True
tree
、new_uncorrected_tree1
、new_uncorrected_tree2
和 new_tree
是同一个对象,因此,它们是相等的,所有与它们相关的操作(例如创建一个字符串representation) 将产生相同的结果。
如果我们最初使用不同的对象,那么结果将是两个完全不同的字符串:
...
tree1 = parse('foo', mode='eval')
tree2 = parse('foo', mode='eval')
new_tree = fix_missing_locations(RewriteName().visit(tree1))
new_uncorrected_tree = RewriteName().visit(tree2)
print(tree1 is tree2) # False
new_tree_str = dump(new_tree, include_attributes=True)
new_uncorrected_tree_str = dump(new_uncorrected_tree, include_attributes=True)
print(dump(new_tree) == dump(new_uncorrected_tree)) # True
print(new_tree_str == new_uncorrected_tree_str) # False
print(tree1 is tree2)
- 因为tree1
和tree2
是不同的对象,所以new_tree
和new_uncorrected_tree
也是不同的对象。
print(dump(new_tree) == dump(new_uncorrected_tree))
- 虽然这些对象的字符串表示(很可能是值)相同。
print(new_tree_str == new_uncorrected_tree_str)
- 在这里我们可以看到 RewriteName
没有填写 new_uncorrected_tree
中的属性,而 fix_missing_locations
填写了,这就是为什么我们看到了差异。
如果我们打印出树,我们可以更清楚地看到差异:
print(dump(new_tree, include_attributes=True, indent=4))
print(dump(new_uncorrected_tree, include_attributes=True, indent=4))
Expression(
body=Subscript(
value=Name(
id='data',
ctx=Load(),
lineno=1,
col_offset=0,
end_lineno=1,
end_col_offset=0),
slice=Constant(
value='foo',
lineno=1,
col_offset=0,
end_lineno=1,
end_col_offset=0),
ctx=Load(),
lineno=1,
col_offset=0,
end_lineno=1,
end_col_offset=0))
Expression(
body=Subscript(
value=Name(id='data', ctx=Load()),
slice=Constant(value='foo'),
ctx=Load()))
但是我们也可以简单地通过从相同的值创建一个相同类型的对象来得到这样的结果:
class RewriteName(NodeTransformer):
def visit_Name(self, node):
return Name(node.id, node.ctx)
这是因为在创建节点对象时,我们没有指定它的所有属性,这正是 parse
函数中发生的情况。
我试图找到一个示例,其中 NodeTransformer
继承人的 visit
与 NodeTransformer
继承人的 visit
不同 并且 在树上使用 fix_missing_locations
。
这是来自 documentation 的示例(由于某些原因它不起作用,即树不会改变,这取决于我们是否应用 fix_missing_locations
):
from ast import *
class RewriteName(NodeTransformer):
def visit_Name(self, node):
return Subscript(
value=Name(id='data', ctx=Load()),
slice=Constant(value=node.id),
ctx=node.ctx
)
tree = parse('foo', mode='eval')
new_tree = fix_missing_locations(RewriteName().visit(tree))
new_uncorrected_tree = RewriteName().visit(tree)
new_tree_str = dump(new_tree, include_attributes=True)
new_uncorrected_tree_str = dump(new_uncorrected_tree, include_attributes=True)
print(new_tree_str == new_uncorrected_tree_str) # True
以上代码问题如下:
...
tree = parse('foo', mode='eval')
new_uncorrected_tree = RewriteName().visit(tree)
new_uncorrected_tree2 = RewriteName().visit(tree)
new_tree = fix_missing_locations(new_uncorrected_tree2)
print(
tree is new_uncorrected_tree, # True
tree is new_uncorrected_tree2, # True
tree is new_tree) # True
tree
、new_uncorrected_tree1
、new_uncorrected_tree2
和 new_tree
是同一个对象,因此,它们是相等的,所有与它们相关的操作(例如创建一个字符串representation) 将产生相同的结果。
如果我们最初使用不同的对象,那么结果将是两个完全不同的字符串:
...
tree1 = parse('foo', mode='eval')
tree2 = parse('foo', mode='eval')
new_tree = fix_missing_locations(RewriteName().visit(tree1))
new_uncorrected_tree = RewriteName().visit(tree2)
print(tree1 is tree2) # False
new_tree_str = dump(new_tree, include_attributes=True)
new_uncorrected_tree_str = dump(new_uncorrected_tree, include_attributes=True)
print(dump(new_tree) == dump(new_uncorrected_tree)) # True
print(new_tree_str == new_uncorrected_tree_str) # False
print(tree1 is tree2)
- 因为tree1
和tree2
是不同的对象,所以new_tree
和new_uncorrected_tree
也是不同的对象。
print(dump(new_tree) == dump(new_uncorrected_tree))
- 虽然这些对象的字符串表示(很可能是值)相同。
print(new_tree_str == new_uncorrected_tree_str)
- 在这里我们可以看到 RewriteName
没有填写 new_uncorrected_tree
中的属性,而 fix_missing_locations
填写了,这就是为什么我们看到了差异。
如果我们打印出树,我们可以更清楚地看到差异:
print(dump(new_tree, include_attributes=True, indent=4))
print(dump(new_uncorrected_tree, include_attributes=True, indent=4))
Expression(
body=Subscript(
value=Name(
id='data',
ctx=Load(),
lineno=1,
col_offset=0,
end_lineno=1,
end_col_offset=0),
slice=Constant(
value='foo',
lineno=1,
col_offset=0,
end_lineno=1,
end_col_offset=0),
ctx=Load(),
lineno=1,
col_offset=0,
end_lineno=1,
end_col_offset=0))
Expression(
body=Subscript(
value=Name(id='data', ctx=Load()),
slice=Constant(value='foo'),
ctx=Load()))
但是我们也可以简单地通过从相同的值创建一个相同类型的对象来得到这样的结果:
class RewriteName(NodeTransformer):
def visit_Name(self, node):
return Name(node.id, node.ctx)
这是因为在创建节点对象时,我们没有指定它的所有属性,这正是 parse
函数中发生的情况。