我试着通读关于兄弟姐妹导入的问题,甚至 软件包文档,但我还没找到答案。

结构如下:

├── LICENSE.md
├── README.md
├── api
│   ├── __init__.py
│   ├── api.py
│   └── api_key.py
├── examples
│   ├── __init__.py
│   ├── example_one.py
│   └── example_two.py
└── tests
│   ├── __init__.py
│   └── test_one.py

示例和测试目录中的脚本如何从 API模块和从命令行运行?

另外,我希望避免对每个文件都使用难看的sys.path.insert。肯定 这可以在Python中完成,对吧?


当前回答

您需要查看import语句是如何在相关代码中编写的。如果examples/example_one.py使用以下import语句:

import api.api

...然后,它期望项目的根目录位于系统路径中。

不需要任何hack(如你所说)就能支持它的最简单的方法就是从顶级目录运行这些例子,就像这样:

PYTHONPATH=$PYTHONPATH:. python examples/example_one.py 

其他回答

存在的问题:

你只是不能让import mypackage在test.py中工作。你将需要一个可编辑的安装,改变到路径,或改变__name__和路径

demo
├── dev
│   └── test.py
└── src
    └── mypackage
        ├── __init__.py
        └── module_of_mypackage.py

--------------------------------------------------------------
ValueError: attempted relative import beyond top-level package

解决方案:

import sys; sys.path += [sys.path[0][:-3]+"src"]

在尝试在test.py中导入之前,请将上述内容放在上面。这是它。你现在可以导入mypackage了。

这在Windows和Linux上都可以工作。它也不会关心从哪个路径运行脚本。它足够短,可以拍打任何你需要它的地方。

为什么有效:

The sys.path contains the places, in order, where to look for packages when attempting imports if they are not found in installed site packages. When you run test.py the first item in sys.path will be something like /mnt/c/Users/username/Desktop/demo/dev i.e.: where you ran your file. The oneliner will simply add the sibling folder to path and everything works. You will not have to worry about Windows vs Linux file paths since we are only editing the last folder name and nothing else. If you project structure is already set in stone for your repository we can also reasonably just use the magic number 3 to slice away dev and substitute src

项目

1.1用户

1.1.1 about.py

1.1.2 init.py

1.2技术

1.2.1 info.py

1.1.2 init.py

现在,如果你想访问User包中的about.py模块,从Tech包中的info.py模块,那么你必须将cmd(在windows中)路径带到项目中,即。 **C:\Users\Personal\Desktop\Project>**根据上面的包示例。你必须从这个路径输入python -m Package_name.module_name 例如,对于上面的包,我们必须做,

c:\用户\个人\桌面\项目>python -m Tech.info

小鬼点

不要在info模块后使用.py扩展名,即python -m Tech.info.py 输入this,其中兄弟包位于同一级别。 -m是标志,要检查它,你可以从CMD python——help

您需要查看import语句是如何在相关代码中编写的。如果examples/example_one.py使用以下import语句:

import api.api

...然后,它期望项目的根目录位于系统路径中。

不需要任何hack(如你所说)就能支持它的最简单的方法就是从顶级目录运行这些例子,就像这样:

PYTHONPATH=$PYTHONPATH:. python examples/example_one.py 

首先,您应该避免使用与模块本身同名的文件。它可能会破坏其他导入。

当你导入一个文件时,解释器首先检查当前目录,然后搜索全局目录。

在示例或测试中,您可以调用:

from ..api import api

七年之后

由于我把答案写在下面,修改sys.;Path仍然是一种快速而肮脏的技巧,适用于私有脚本,但是已经有了一些改进

安装包(在virtualenv中或不在virtualenv中)会给你想要的,尽管我建议使用pip来完成,而不是直接使用setuptools(并使用setup.cfg存储元数据) 使用-m标志并作为包运行也可以(但是如果您想将工作目录转换为可安装包,则会有点尴尬)。 具体来说,对于测试,pytest能够在这种情况下找到api包,并负责sys. exe。给你的路径技巧

所以这取决于你想做什么。但是,在您的情况下,由于您的目标似乎是在某种程度上制作一个适当的包,因此通过pip -e安装可能是您的最佳选择,即使它还不完美。

旧的答案

正如在其他地方已经说过的,可怕的事实是,你必须做一些丑陋的hack来允许从__main__模块的兄弟模块或父包导入。该问题在PEP 366中有详细说明。PEP 3122试图以更合理的方式处理导入,但Guido拒绝了它

唯一的用例似乎是运行发生的脚本 在一个模块的目录中,我总是把它看作一个 反模式。

(在这里)

不过,我经常使用这种模式

# Ugly hack to allow absolute import from the root folder
# whatever its name is. Please forgive the heresy.
if __name__ == "__main__" and __package__ is None:
    from sys import path
    from os.path import dirname as dir

    path.append(dir(path[0]))
    __package__ = "examples"

import api

这里的路径[0]是运行脚本的父文件夹,目录(路径[0])是顶级文件夹。

虽然我还不能使用相对导入,但它确实允许从顶层(在示例api的父文件夹中)进行绝对导入。