PEP8 - 使用sys.path导入不在文件顶部

Luk*_*lor 57 python pep8 python-3.x

问题

PEP8有一条关于将导入放在文件顶部的规则:

导入总是放在文件的顶部,就在任何模块注释和文档字符串之后,以及模块全局变量和常量之前.

但是,在某些情况下,我可能想要做以下事情:

import sys
sys.path.insert("..", 0)

import my_module
Run Code Online (Sandbox Code Playgroud)

在这种情况下,pep8命令行实用程序标记我的代码:

E402模块级别导入不在文件顶部

实现PEP8符合sys.path修改的最佳方法是什么?

为什么

我有这个代码,因为我遵循Hitchhiker的Python指南中给出的项目结构.

该指南建议我有一个my_module文件夹,与文件夹分开tests,两者都在同一目录中.如果我要访问my_moduletests,我想我需要添加..sys.path

ast*_*rga 58

如果只有少量导入,您可以忽略这些import行上的PEP8 :

import sys
sys.path.insert("..", 0)
import my_module  # noqa: E402
Run Code Online (Sandbox Code Playgroud)

  • 如果您从同一路径有多个导入,则将“# noqa:E402”放在“sys.path.insert ...”行上会更短 (6认同)
  • 我更喜欢更明确,例如指定违反规则,例如`#noqa:E402`.([源(http://flake8.pycqa.org/en/3.1.1/user/ignoring-errors.html#in-line-ignoring-errors)) (5认同)

Rol*_*ith 41

我经常在foo/tests项目的子目录中有多个带有测试的文件,而我正在测试的模块是foo/src.要在foo/tests没有导入错误的情况下运行测试,我创建一个foo/tests/pathmagic.py看起来像这样的文件;

"""Path hack to make tests work."""

import os
import sys

bp = os.path.dirname(os.path.realpath('.')).split(os.sep)
modpath = os.sep.join(bp + ['src'])
sys.path.insert(0, modpath)
Run Code Online (Sandbox Code Playgroud)

在每个测试文件中,我然后使用

import pathmagic  # noqa
Run Code Online (Sandbox Code Playgroud)

作为第一个进口."noqa"评论阻止pycodestyle/ pep8抱怨未使用的导入.

  • @Chung-YenHung 请记住,pycodestyle/pep8 警告是建议性的,而不是语法错误或异常。您可以选择忽略它们。我通过在导入后添加“noqa”评论来更新我的答案。 (3认同)
  • 这很酷,但是仍然存在“导入但未使用[F401]”的问题。 (2认同)
  • 我想在那个 pathmagic 模块中创建一个虚拟函数并从测试模块调用它会解决这个问题,但我希望有更干净的东西...... (2认同)

Peu*_*ele 9

还有另一种解决方法.

import sys
... all your other imports...

sys.path.insert("..", 0)
try:
    import my_module
except:
    raise
Run Code Online (Sandbox Code Playgroud)

  • @ darkdefender27的想法是将所有需要PYTHONPATH的导入放在`try`主体中,并将​​所有其他内容(不依赖于此)放在上面。 (2认同)

sha*_*unc 9

这个问题已经有几个可行的解决方案,但如果您有多个非初始导入,并且不想对每个导入进行注释# noqa: E402(或使用其他建议之一),则以下方法适用于整个块:

import sys
sys.path.insert("..", 0)

if True:  # noqa: E402
    import my_module_1
    import my_module_2
    ...
Run Code Online (Sandbox Code Playgroud)


its*_*dok 6

我刚刚在类似的问题上苦苦挣扎,我想我找到了一个比公认的答案稍微好一点的解决方案。

创建一个执行实际 sys.path 操作的模块,但在上下文管理器pathmagic中进行更改:

"""Path hack to make tests work."""

import os
import sys

class context:
    def __enter__(self):
        bp = os.path.dirname(os.path.realpath('.')).split(os.sep)
        modpath = os.sep.join(bp + ['src'])
        sys.path.insert(0, modpath)

    def __exit__(self, *args):
        pass
Run Code Online (Sandbox Code Playgroud)

然后,在您的测试文件中(或任何您需要的地方),您可以:

import pathmagic

with pathmagic.context():
    import my_module
    # ...
Run Code Online (Sandbox Code Playgroud)

这样你就不会收到 flake8/pycodestyle 的任何抱怨,你不需要特殊的注释,而且结构似乎很有意义。

为了更加整洁,请考虑实际恢复块中的路径__exit__,尽管这可能会导致延迟导入的问题(如果将模块代码放在上下文之外),所以可能不值得这么麻烦。


编辑:刚刚在另一个问题的答案中看到了一个更简单的技巧:assert pathmagic在导入下添加以避免noqa评论。