2

I'm writing a pylint checker and I need to differentiate between an import that is a sibling import of a package and an import of a function or class.

Example of sibling import:

from . import sibling_package

Example of a function import:

from numpy import array

The latter example I want to flag, while the former I want to allow, so I need to be able to tell the difference between the two.

I'm currently using:

modspec = importlib.util.find_spec('numpy', 'array')

That returns a ModuleSpec, but I'm unclear how I can get to the goal of identifying the import array as a module vs. a function/class. In this example it is a function import, and thus should be flagged.

4

1 回答 1

2

这不是您可以从导入行轻松检测到的。Python 是高度动态的,直到运行时才能知道导入解析为哪种类型的对象。模块规范无法告诉您此信息,因为模块上的属性可以解析为任何内容(包括另一个模块)。

我可以看到的替代方案是:

  • 进行实际导入,然后测试对象类型。

    这并非没有风险,进口可能会产生副作用。导入模块包括执行顶级语句。这些副作用可能很轻微,例如在不满足依赖项时将一个对象替换为另一个对象(这try: from itertools import zip_longestexcept ImportError: from itertools import izip_longest as ziplongest一个微不足道的 Python 2 与 Python 3 依赖项检查),但潜在的导入可能会更改文件系统!

    进口也会减慢检查速度。导入一个类似numpypandas可以拉入大量附加模块的模块。您通常希望保持快速linting ,否则开发人员往往不会打扰并完全跳过 linting。

  • 保留已知模块的列表。对于您知道的那些模块,如果他们从模块而不是模块本身导入名称,请抱怨。这很快,并且可以捕获大多数常见情况。您可以使用从被检查模块周围的文件系统中收集到的内容来扩充列表。换句话说,目标是快速和足够好,并接受一些新进口的失误。

  • 仅在直接调用导入的名称时才抱怨。注册所有导入的名称,如果 AST 包含Call该名称的节点,那么您知道它们导入了函数或类。from foo import bar,然后spam = bar('baz')是一个明确的指标,bar不是一个模块。

于 2018-08-29T09:40:23.443 回答