Это может быть не идеально, но оно должно делать то, что вам нужно
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
, но есть и другие, которые необходимо учитывать, если этого требует ваше решение.