我正在编写pylint检查器,我需要区分是同级包导入还是函数或类的导入。
同级导入示例:
from . import sibling_package
函数导入示例:
from numpy import array
我要标记后一个示例,而我想允许前一个示例,因此我需要能够分辨出两者之间的区别。
我当前正在使用:
modspec = importlib.util.find_spec('numpy', 'array')
返回一个ModuleSpec
,但是我不清楚如何实现将导入array
识别为模块还是功能/类的目标。在此示例中,它是函数导入,因此应进行标记。
答案 0 :(得分:2)
这不是您可以轻松地从导入行中检测到 的内容。 Python是高度动态的,直到运行时您才能知道导入解析为哪种类型的对象。模块规范无法告诉您此信息,因为模块上的属性可以解析为任何内容(包括另一个模块)。
我可以看到的替代方法是:
做实际的导入,然后测试对象类型。
这并非没有风险,进口可以具有副作用。导入模块包括执行顶层语句。这些副作用可能很轻微,例如在不满足依赖项时将一个对象替换为另一个对象(try: from itertools import zip_longest
,except ImportError: from itertools import izip_longest as ziplongest
是琐碎的Python 2 vs. Python 3依赖项检查),但可能会导致导入文件系统更改!
导入也将减慢检查速度。导入numpy
或pandas
之类的模块可能会引入大量其他模块。通常,您希望保持linting fast 的速度,否则开发人员将不会理会并完全跳过lint。
保留已知模块的列表。对于您知道的那些模块,请抱怨它们是否从模块而不是模块本身导入名称。这是快速的,并且将捕获大多数常见情况。您可以使用可以从要插入模块的文件系统中收集的内容来扩充列表。换句话说,目标是足够好并且接受一些新进口产品的缺失。
仅在直接调用导入的名称时抱怨。注册所有导入的名称,如果AST包含该名称的Call
节点,则您知道它们导入了一个函数或类。 from foo import bar
,然后稍后在spam = bar('baz')
上清楚地表明bar
不是模块。