该
ast模块可以很容易地做到这一点。如果我们假设源存储在名为
source(可以从文件读取)的变量中:
import astroot = ast.parse(source)names = sorted({node.id for node in ast.walk(root) if isinstance(node, ast.Name)})这样就失去了获得唯一性和友好的显示顺序的顺序,但是如果您不需要唯一性但想要排序,则可以只使用列表推导或生成器表达式来代替集合推导。结果
list是:
['a', 'b', 'c', 'do_something', 'f', 'myList', 'range', 'someMethod', 'something', 'x']
与到目前为止发布的其他解决方案不同,这将递归到类和函数中以在其中使用名称,并且不需要您导入要检查的模块或类,也不需要您自己实现递归处理;任何语法上有效的Python代码都可以使用。
奇怪的是,在Python 3(替换有效的
['a', 'b', 'c', 'do_something', 'f', 'myList', 'print', 'range', 'someMethod', 'something']
它添加了
x。您没有要求
x(接收到的参数
someMethod),并且在Python
3上也没有产生它。函数原型中的名称似乎并未在
ast.Name那里创建节点,请参见图。您可以
ast.FunctionDef从中的
arg每个条目的属性将信息从节点中拉出
list
node.args.args,但是它可能仍然不全面。我怀疑可能会遗漏其他与定义相关的名称,例如在带有继承的类声明中。您需要仔细研究一些示例,以确保您检查了所有内容(假设您想要类似的东西
x并且想要在Python
3上工作)。
就是说,
x如果您引用它,它将很好地显示出来;如果您
do_something除了接收和丢弃它以外将其传递给或使用它,它还会显示出来。
您还可以通过将测试扩展到以下内容来努力处理仅分配给未使用的名称(排除
do_something,
range):
names = sorted({node.id for node in ast.walk(root) if isinstance(node, ast.Name) and not isinstance(node.ctx, ast.Load)})但这也会下降
someMethod(在Py2和Py3中),因为定义本身不会产生
ast.Name,而只是使用它会产生。如此反复,你就必须钻研得更深一些,到
ast.Node内部的
ast.FunctionDef,
ast.ClassDef等拿到未的名字
walk直接-
ed。



