Python 类型化ast节点评估 前言
有一个用于跨Python AST解析和处理(例如,在1中) 问题 我想知道是否有一种方法可以像编译标准节点一样编译节点 因为这是有效的Python 类型化ast节点评估 前言,python,python-3.x,abstract-syntax-tree,Python,Python 3.x,Abstract Syntax Tree,有一个用于跨Python AST解析和处理(例如,在1中) 问题 我想知道是否有一种方法可以像编译标准节点一样编译节点 因为这是有效的 import ast code = compile(ast.parse('print("Hello World!")'), '<ast>', 'exec') eval(code) # Hello World! 导入ast code=compile(ast.parse('print(“Hello World!”),'用于在ty
import ast
code = compile(ast.parse('print("Hello World!")'), '<ast>', 'exec')
eval(code) # Hello World!
导入ast
code=compile(ast.parse('print(“Hello World!”),'用于在typed\u ast.ast27
和typed\u ast.ast3
转换之间进行转换,但找不到类似的typed\u ast.ast3
->ast
转换
我也知道,但它会将源代码创建为字符串,这不是一个选项,因为我使用了一些使AST可编译但不可解析的黑客
最后,还有哪些医生这么说
…如果需要求值*注释字段*必须设置为False
所以看起来可能有一种方法可以评估生成的转储字符串?或者有一种方法可以从ast
加载此字符串
或者我应该编写自己的ast3.NodeTransformer
类来执行这种转换吗
1:到目前为止,我使用自定义ast3.NodeTransformer的解决方案(在Python3.5上测试)
试验
从输入的ast导入ast3
code=compile(TypedToPlain().visit(ast3.parse('print(“helloworld!”))),
“执行官”
eval(代码)#你好,世界!
在Python3.3上不起作用(在ast.Call
字段中存在差异)
from typed_ast import ast3
code = compile(ast3.parse('print("Hello World!")'), '<ast>', 'exec') # raises exception
eval(code)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: compile() arg 1 must be a string, bytes or AST object
import ast
from functools import partial
from itertools import chain
from typed_ast import ast3
def to_visitor(cls):
def none(_):
return None
try:
plain_cls = getattr(ast, cls.__name__)
except AttributeError:
# node type is not found in `ast` module, skipping
return none
def visit(self, node):
node = self.generic_visit(node)
result = plain_cls(*map(partial(getattr, node), plain_cls._fields))
return ast3.copy_location(result, node)
return visit
def to_subclasses(cls,
*,
deep=True):
result = cls.__subclasses__()
yield from result
if not deep:
return
subclasses_factory = partial(to_subclasses,
deep=deep)
yield from chain.from_iterable(map(subclasses_factory, result))
class TypedToPlain(ast3.NodeTransformer):
visitors = {'visit_' + cls.__name__: to_visitor(cls)
for cls in set(to_subclasses(ast3.AST))}
def __getattr__(self, name):
return partial(self.visitors[name], self)
def generic_visit(self, node):
for field, old_value in ast3.iter_fields(node):
if isinstance(old_value, list):
new_values = []
for value in old_value:
if isinstance(value, ast3.AST):
value = self.visit(value)
if value is None:
continue
elif not isinstance(value, ast.AST):
new_values.extend(value)
continue
new_values.append(value)
old_value[:] = new_values
elif isinstance(old_value, ast3.AST):
new_node = self.visit(old_value)
if new_node is None:
delattr(node, field)
else:
setattr(node, field, new_node)
return node
from typed_ast import ast3
code = compile(TypedToPlain().visit(ast3.parse('print("Hello World!")')),
'<ast>', 'exec')
eval(code) # Hello World!