如何从Python的AST中获取变量的类型?

4
假设我想从已生成的AST树中获取所有变量的类型,这些变量来自一些源代码 - 我该如何做呢?例如,假设在我的源代码中有类似于i = 5这样的内容。如何从抽象语法树中确定i的类型是整数?
我尝试了type()函数;然而,它在这种情况下不起作用。
3个回答

3
如其他帖子所述,没有简单的方法可以在不进行语法树结构深度分析的情况下实现此操作。然而,Python ast模块并未提供相关功能。

您仍然可以使用Logilab的Astng1,该模块是Pylint2的基础,并提供静态推断功能。

以下是一个快速示例:

from logilab.astng.builder import ASTNGBuilder
builder = ASTNGBuilder()
astng = builder.string_build('i = 1', __name__, '<string>')
assnode = astng['']
print [(inf.value, type(inf.value)) for inf in assnode.infer()]

当然,您需要深入了解API以获取更多实际用例。您仍然可以向python-projects@lists.logilab.org发送邮件以获取帮助。

2
如其他帖子所指出的那样,在动态类型语言中这并不容易。你不能像在C或Java中一样追踪分配到静态类型声明,然而,我们通常可以合理地确定类型。
假定作用域规则允许我们确定在问题被提出时哪个i(或哪组i)可能被访问/更新/绑定。然后可以对所有可能被赋值的值进行分析(一个特别简单的情况是当i仅绑定到函数定义时)。这些类型在类型格中的上限就是i的“类型”。是的,在某些情况下它可能是“任何东西”,但在大多数良好编写的程序中,即使是动态变量,程序员也有一个“狭窄”的类型,通常是原始语言类型(比如,“int”)。否则,程序员将无法合理地编写算法(你的数组索引有时不是整数吗?)。
您需要对程序进行某种保守的分析来确定此上限类型。(显然,您可以进行简单的分析,并得出无用的结论,即变量可以是“任何”类型)。我认为这是一个不令人满意的答案。
完成所有这些分析的机制非常复杂(您需要全局流分析和一些确定可以动态加载的内容),我怀疑Python的AST包是否能够做到这一点。

嗯,好的,假设我得到的 AST,是来自于代码某个时间点上的一个节点: "a = 2" Module([Assign([Name('a', Store())], Num(2))... 你可以看到,AST 似乎显示了赋值的值的类型为数字(num) -- 是否有任何方法或函数,我可以在该节点上使用以获取此信息? - Nonomus
“什么,你的数组索引有时不是整数?”在我编写的某些代码中,这种情况可能会发生,因为我的数组有时不是一个“列表”,而是一个“字典”。 - Ben
@Nonomous:在代码的那个点上,a的“类型”明显是“two”(nat的子集,int的子集,rational的子集,real的子集,imaginary的子集,...)。我不了解Python或AST模块,但您可以通过检查表达式来确定“a”的类型。当它说“a=a+1”时,除非您检查所有其他数据流到此点的a值,否则您将遇到麻烦。您需要一个数据流分析模块。我怀疑它是否是Python的AST模块的一部分。可能有其他人已经构建了它,但他们必须站出来说话。 - Ira Baxter
@Ben:对于Python,你必须担心大小写问题,但我认为我的观点很清楚。 - Ira Baxter
@IraBaxter:您的观点很明确,您非常正确,在大多数Python代码中,给定变量只会包含一种类型的值,或者可能是几种类型之一。但是,您必须进行完整的程序分析才能观察到这一点,即使是变量真正可以具有几乎任何类型的地方,也意味着任何接触它的东西都几乎可以具有任何类型,以此类推,直到它污染了程序的大部分。对于任何具有条件导入或动态类创建的程序,您需要解决停机问题,以列举程序中的所有类型。 - Ben
显示剩余4条评论

1

你不能这样做,因为Python的变量没有类型,才有类型。

这就是动态类型的工作原理。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接