当遍历AST树时,跟踪上下文;从全局上下文开始,然后遇到
FunctionDef
、
ClassDef
或
Lambda
节点时,将该上下文记录为堆栈(在退出相关节点时弹出堆栈)。
您可以仅查看全局上下文中的
Name
节点。您也可以跟踪
global
标识符(我会使用每个堆栈级别的集合)。
使用
NodeVisitor
子类 :
import ast
class GlobalUseCollector(ast.NodeVisitor):
def __init__(self, name):
self.name = name
self.context = [('global', ())]
def visit_FunctionDef(self, node):
self.context.append(('function', set()))
self.generic_visit(node)
self.context.pop()
visit_AsyncFunctionDef = visit_FunctionDef
def visit_ClassDef(self, node):
self.context.append(('class', ()))
self.generic_visit(node)
self.context.pop()
def visit_Lambda(self, node):
self.context.append(('function', ()))
self.generic_visit(node)
self.context.pop()
def visit_Global(self, node):
assert self.context[-1][0] == 'function'
self.context[-1][1].update(node.names)
def visit_Name(self, node):
ctx, g = self.context[-1]
if node.id == self.name and (ctx == 'global' or node.id in g):
print('{} used at line {}'.format(node.id, node.lineno))
示例(假设您的示例代码在t
中的AST树已知):
>>> GlobalUseCollector('x').visit(t)
x used at line 1
x used at line 10
x used at line 12
x used at line 13
在函数中使用global x
:
>>> u = ast.parse('''\
... x = 20
...
... def g():
... global x
... x = 0
... for x in range(10):
... x += 10
... return x
...
... g()
... for x in range(10):
... pass
... x += 1
... print(x)
... ''')
>>> GlobalUseCollector('x').visit(u)
x used at line 1
x used at line 5
x used at line 6
x used at line 7
x used at line 8
x used at line 11
x used at line 13
x used at line 14
async def
函数定义visit_AsyncFunctionDef(self, node)
。 - pahazvisit_AsyncFuncDef = visit_FuncDef
。 - Martijn Pieters