我在字符串中有一些python代码,我将其编译为代码对象。
如何在不运行代码的情况下获取变量名称和类型的列表(例如使用 AST?
所有变量都在global
范围内,尽管在某些命名函数中做类似的事情也可能很有用,例如draw()
.
# Example source:
source_code = """
a = 1
b = "hello world"
print(a)
print(b)
"""
code_obj = compile(source_code, "<string>", "exec")
# At this point I would like to know that 'a' is an int and 'b' is a str
exec(code_obj)
这可能并不完美,但它应该做你所追求的
import ast
class ASTExplorer:
def __init__(self, source):
self.tree = ast.parse(source, mode="exec")
self.result = list()
class ASTResult:
def __init__(self, var, expr, vType):
self.var = var
self.expression = expr
self.vType = vType
def _getLineAssignment(self, lineno):
return next((node for node in ast.walk(self.tree) if isinstance(node, ast.Name) and node.lineno == lineno), None)
def getVariables(self):
for node in ast.walk(self.tree):
if not isinstance(node, ast.Assign):
continue
nodeValue = node.value
nodeVariable = self._getLineAssignment(node.lineno).id
if(isinstance(nodeValue, ast.Constant)):
nodeExpression = node.value.value
self.result.append(self.ASTResult(nodeVariable, nodeExpression, type(nodeExpression)))
continue
elif(isinstance(nodeValue, ast.Call)):
callFunc = nodeValue.func.id
callArgs = "(" + (", ".join([str(x.value) for x in nodeValue.args])) + ")"
self.result.append(self.ASTResult(nodeVariable, f"{callFunc}{callArgs}", ast.Call))
#elif... other type handling
return self.result
你会这样使用它
source_code = """
myRangeVar = range(1, 10)
myIntVar = 1
myStrVar = "hello world"
myTest = fakeFunct()
myTestTwo = fakeFunct(20)
print(a)
print(b)
"""
explorer = ASTExplorer(source_code)
for result in explorer.getVariables():
print(f"Found variable '{result.var}' with a value of '{result.expression}' (type: '{result.vType.__name__}')")
这导致
Found variable 'myRangeVar' with a value of 'range(1, 10)' (type: 'Call')
Found variable 'myIntVar' with a value of '1' (type: 'int')
Found variable 'myStrVar' with a value of 'hello world' (type: 'str')
Found variable 'myTest' with a value of 'fakeFunct()' (type: 'Call')
Found variable 'myTestTwo' with a value of 'fakeFunct(20)' (type: 'Call')
我#elif... other type handling
添加了一个注释,因为它目前仅处理类型Constant
和Call
的声明,但如果您的解决方案需要,还有其他需要考虑的声明。