2

在 Linux 环境中,我在名为 的文件夹中有以下三个文件utils

  1. 一个空文件__init__.py

  2. mymain.py具有以下内容的文件:

    from mytool import foo
    
  3. mytool.py具有以下内容的文件:

    from subprocess import check_output
    
    def foo():
        print("Hello World")
    

现在我使用以下设置创建一个虚拟环境:

astroid==2.4.2
isort==5.7.0
lazy-object-proxy==1.4.3
packaging==20.9
pylint==2.6.0
pyparsing==2.4.7
six==1.15.0
toml==0.10.2
typed-ast==1.4.2
wrapt==1.12.1

然后我对该文件夹运行 pylint 检查

pylint utils

或者

pylint --disable=C,R,W utils  # only the error is of interest

它应该返回 10 分。

当您现在将版本升级astroid到 2.5.0 并再次运行检查时,您会收到错误消息:

************* Module utils.mymain
utils/mymain.py:2:0: E0401: Unable to import 'mytool' (import-error)

如HERE所指出的,是否由于不推荐使用的 importlib 方法而改变了行为?

趣味事实

如果您删除文件中未使用的导入语句,即使使用版本 2.4.2 mytool.py,您也会收到相同的导入错误。astroid

为什么; 未使用的导入如何影响pylint检查结果?

提示:我有两个问题。

4

2 回答 2

2

这个问题是不可重现的,所以很难说astroid版本和未使用的 import 语句是否是问题的核心,但我们可以尝试调查其他途径,以更好地了解这里发生了什么。


简而言之

执行pylint --disable=C,R,W utils的行为就像将utils作为模块导入一样,导致绝对导入 from mytool import foo失败。


详细地

我相信您希望Pylint能够返回完美分数,因为python3 utils/mymain.py它是从父文件夹或python3 mymain.pyutils文件夹工作执行的。

唉,这些执行方法之所以有效,是因为sys.path[0]初始化utils文件夹的路径。因此,绝对导入语句from mytool import foo成功,因为包mytoolsys.path.

但是,当执行Pylint时,其__main__.py文件被视为主模块,并且utils文件夹的路径不再包含在其中sys.path的任何位置,并且绝对导入失败。

以下是导致pylint --disable=C,R,W utils返回完美分数的三种不同方法:

  1. 将导入语句编辑为相对的,即from .mytool import foo. 请注意,此更改保证您将脚本作为来自父文件夹(例如python3 -m utils.mymain)的模块执行。

  2. utils文件夹添加到PYTHONPATH执行脚本sys.path之前或到达绝对导入语句之前。

    但是,如果您确实更喜欢这种使用绝对导入的方法,我建议重新安排项目结构以反映设计良好的模块并正确导入它(例如from <module>.utils.mytool import foo)。当然,这需要在本地安装模块或操作路径以支持导入。

  3. 尝试使用Python 2运行。由于Python 2中不推荐使用隐式相对导入的行为,因此无需任何更改即可工作。


解决您关于astroid模块和未使用的 import 语句对Pylint检查结果的影响的问题:

  • 由于Pylint依赖于astroid模块才能工作,因此 astroid 模块中的错误可能会以意想不到的方式影响Pylint检查的结果,包括您描述的方式。

  • 由于Pylint是在整个utils文件夹上执行的,因此utils/mytool.py中未使用的导入语句可能会显示为警告,但它不应以您描述的方式改变Pylint检查的结果(除非它触发一些意外行为在有缺陷的astroid版本中)。

因此,带有或不带有未使用的 import 语句的有缺陷的astroid版本可能会产生意想不到的结果。但是,由于该问题不可重现,因此很难研究这里到底发生了什么。


Pylint的官方文档建议对这种神秘行为的另一种解释是安装的模块与测试的模块同名:

你应该给Pylint一个Python包或模块的名称。Pylint不会导入这个包或模块,尽管使用Python内部来定位它们,因此受到相同的规则和配置的约束。您应该注意您的PYTHONPATH,因为分析模块的已安装版本而不是开发版本是一个常见错误。

于 2021-03-12T22:45:26.003 回答
-1

尝试更改导入语句

从:

from mytool import foo

至:

from .mytool import foo

模块名称中的点用于相对模块导入(Ref Link Here)。

于 2021-03-17T14:26:43.303 回答