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

结构如下:

├── 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中完成,对吧?


当前回答

项目

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

对于2021年的读者:如果你对pip没有信心,请安装-e:

考虑一下这个层次结构,正如Python 3中相对导入的答案所推荐的那样:

MyProject
├── src
│   ├── bot
│   │   ├── __init__.py
│   │   ├── main.py
│   │   └── sib1.py
│   └── mod
│       ├── __init__.py
│       └── module1.py
└── main.py

main.py的内容,这是起点,我们在这里使用绝对导入(没有前导点):

from src.bot import main


if __name__ == '__main__':
    main.magic_tricks()

bot/main.py的内容,它利用了显式的相对导入:

from .sib1 import my_drink                # Both are explicit-relative-imports.
from ..mod.module1 import relative_magic

def magic_tricks():
    # Using sub-magic
    relative_magic(in=["newbie", "pain"], advice="cheer_up")
    
    my_drink()
    # Do your work
    ...

原因如下:

当执行python MyProject/main.py时,/到/MyProject的路径被添加到sys.path中。 绝对导入import src。机器人会读的。 从…mod部分意味着它将上升一级到MyProject/src。 我们能看看吗?是的,因为路径/to/MyProject被添加到sys.path中。

所以重点是:

我们应该把主脚本放在MyProject/src旁边,因为当做相对引用时,我们不会离开src,绝对导入导入src。为我们提供合适的作用域:src/ scope。

参见:ModuleNotFoundError:没有名为“sib1”的模块

如果您正在使用pytest,那么pytest文档描述了如何从单独的测试包引用源包的方法。

建议的项目目录结构为:

setup.py
src/
    mypkg/
        __init__.py
        app.py
        view.py
tests/
    __init__.py
    foo/
        __init__.py
        test_view.py
    bar/
        __init__.py
        test_view.py

setup.py文件的内容:

from setuptools import setup, find_packages

setup(name="PACKAGENAME", packages=find_packages())

以可编辑模式安装软件包:

pip install -e .

这篇文章引用了Ionel Cristian matrie什的博客文章。

在主文件中添加以下内容:

import sys
import os 
sys.path.append(os.path.abspath(os.path.join(__file__,mainScriptDepth)))

mainScriptDepth =主文件从项目根目录的深度。

这是你的案例mainScriptDepth = "../../"。然后,您可以通过指定路径(从api。API import *)从你的项目的根。

我做了一个示例项目来演示如何处理这个问题,这实际上是另一个系统。路径hack如上所示。Python兄弟导入示例,它依赖于:

如果__name__ == '__main__': import OS import sys sys.path.append(OS .getcwd())

只要你的工作目录保持在Python项目的根目录,这似乎是非常有效的。