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

时间:2016-04-24 19:35:39

标签: python python-3.x pep8

问题

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

  

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

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

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

import my_module

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

  

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

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

为什么

我有这段代码,因为我正在关注the project structure中提供的The Hitchhiker's Guide to Python

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

7 个答案:

答案 0 :(得分:51)

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

import sys
sys.path.insert("..", 0)
import my_module  # noqa: E402

答案 1 :(得分:36)

我的项目的子目录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)

在每个测试文件中,我都会使用

import pathmagic  # noqa

作为第一个导入。 “noqa”评论会阻止pycodestyle / pep8抱怨未使用的导入。

答案 2 :(得分:8)

还有另一种解决方法。

using Newtonsoft.Json;
using System;
using System.Collections.Generic;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            string JSONInput = @"{""SN0124"": {
                                    ""category1"": 0,
                                    ""output"": {
                                        ""ABC"": [], 
                                        ""DEF"": 0, 
                                        ""GHI"": ""ABDEF""
                                    },
                                    ""category2"": 0, 
                                    ""category3"": 0
                                },
                                ""SN0123"": {
                                    ""category1"": 0, 
                                    ""output"": {
                                        ""ABC"": [""N1"", ""N2""], 
                                        ""DEF"": 0, 
                                        ""GHI"": ""ABDEF""
                                    },
                                    ""category2"": 0, 
                                    ""category3"": 0
                                }}";
            Dictionary<string, Pets> deserializedProduct = JsonConvert.DeserializeObject<Dictionary<string, Pets>>(JSONInput);
            Console.ReadKey();
        }
    }

    public class Output
    {
        public string[] ABC { get; set; }
        public int DEF { get; set; }
        public string GHI { get; set; }
    }

    public class Pets
    {

        public int category1 { get; set; }

        public Output output { get; set; }

        public int category2 { get; set; }
        public int category3 { get; set; }

    }
}

答案 3 :(得分:4)

我只是在努力解决类似的问题,我认为我找到了一个比接受的答案更好的解决方案。

创建一个pathmagic模块,用于执行实际的sys.path操作,但在context manager内进行更改:

"""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

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

import pathmagic

with pathmagic.context():
    import my_module
    # ...

这样你就不会得到flake8 / pycodestyle的任何投诉,你不需要特别的评论,结构似乎也有意义。

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

编辑:只是在answer to a different question中看到了一个更简单的技巧:在导入下添加assert pathmagic以避免noqa评论。

答案 4 :(得分:2)

为符合pep8,您应该包含python路径的项目路径,以便执行相对/绝对导入。

为此,您可以查看以下答案:How to Preview Image, get file size, image height and width before upload?

答案 5 :(得分:2)

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

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

if True:  # noqa: E402
    import my_module_1
    import my_module_2
    ...

答案 6 :(得分:1)

您是否已经尝试过以下操作:

import sys
from importlib import import_module

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

# import module
my_mod = import_module('my_module')

# get method or function from my_mod
my_method = getattr(my_mod , 'my_method')