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

结构如下:

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


当前回答

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

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

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

其他回答

为了防止在Eclipse上使用Pydev的人在这里结束:您可以使用Project->Properties将兄弟的父路径(以及调用模块的父路径)添加为外部库文件夹,并在左侧菜单Pydev- pythonpath下设置外部库。然后你可以从你的兄弟导入,例如from sibling import some_class。

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

import api.api

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

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

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

下面是我在tests文件夹的Python文件顶部插入的另一个替代方案:

# Path hack.
import sys, os
sys.path.insert(0, os.path.abspath('..'))

厌倦了系统。路径黑客吗?

有很多可用的sys.path.append -hacks,但我发现了另一种解决问题的方法。

总结

将代码打包到一个文件夹中(例如packaged_stuff) 创建setup.py脚本,其中使用setuptools.setup()。(参见下面的minimal setup.py) 使用Pip install -e <myproject_folder>将包安装到可编辑状态 从packaged_stuff导入using。Modulename import function_name


设置

起点是您提供的文件结构,包装在名为myproject的文件夹中。

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

我会打电话给。在我的例子中,它位于C:\tmp\test_imports\。

api.py

作为测试用例,让我们使用下面的./api/api.py

def function_from_api():
    return 'I am the return value from api.api!'

test_one.py

from api.api import function_from_api

def test_function():
    print(function_from_api())

if __name__ == '__main__':
    test_function()

尝试运行test_one:

PS C:\tmp\test_imports> python .\myproject\tests\test_one.py
Traceback (most recent call last):
  File ".\myproject\tests\test_one.py", line 1, in <module>
    from api.api import function_from_api
ModuleNotFoundError: No module named 'api'

尝试相对导入也不会起作用:

使用from ..api。API导入函数from_api的结果为

PS C:\tmp\test_imports> python .\myproject\tests\test_one.py
Traceback (most recent call last):
  File ".\tests\test_one.py", line 1, in <module>
    from ..api.api import function_from_api
ValueError: attempted relative import beyond top-level package

步骤

创建一个setup.py文件到根目录


setup.py的内容是*

from setuptools import setup, find_packages

setup(name='myproject', version='1.0', packages=find_packages())

使用虚拟环境


如果您熟悉虚拟环境,请激活一个,然后跳转到下一步。使用虚拟环境并不是绝对必需的,但从长远来看,它们确实会帮助你(当你有多个正在进行的项目时)。最基本的步骤是(在根文件夹中运行)

创建虚拟环境 Python -m venv venv 激活虚拟环境 ./venv/bin/activate (Linux, macOS)或./venv/Scripts/activate (Win)

要了解更多信息,请参考谷歌“python virtual env tutorial”或类似内容。除了创建、激活和取消激活之外,您可能永远不需要任何其他命令。

创建并激活虚拟环境后,控制台应该在括号中给出虚拟环境的名称

PS C:\tmp\test_imports> python -m venv venv
PS C:\tmp\test_imports> .\venv\Scripts\activate
(venv) PS C:\tmp\test_imports>

你的文件夹树应该看起来像这样**

.
├── myproject
│   ├── api
│   │   ├── api_key.py
│   │   ├── api.py
│   │   └── __init__.py
│   ├── examples
│   │   ├── example_one.py
│   │   ├── example_two.py
│   │   └── __init__.py
│   ├── LICENCE.md
│   ├── README.md
│   └── tests
│       ├── __init__.py
│       └── test_one.py
├── setup.py
└── venv
    ├── Include
    ├── Lib
    ├── pyvenv.cfg
    └── Scripts [87 entries exceeds filelimit, not opening dir]

PIP在可编辑状态下安装项目


使用pip安装你的顶级包myproject。诀窍是在进行安装时使用-e标志。通过这种方式,它被安装在可编辑状态下,对.py文件的所有编辑都将自动包含在已安装的包中。

在根目录下运行

PIP install -e。(注意这个点,它代表“当前目录”)

您还可以看到它是通过使用pip freeze安装的

(venv) PS C:\tmp\test_imports> pip install -e .
Obtaining file:///C:/tmp/test_imports
Installing collected packages: myproject
  Running setup.py develop for myproject
Successfully installed myproject
(venv) PS C:\tmp\test_imports> pip freeze
myproject==1.0

添加。。导入文件中


注意,您必须添加myproject。只能输入到其他无法工作的输入中。没有setup.py和pip安装的导入仍然可以正常工作。请参见下面的示例。


测试解决方案

现在,让我们使用上面定义的api.py和下面定义的test_one.py测试解决方案。

test_one.py

from myproject.api.api import function_from_api

def test_function():
    print(function_from_api())

if __name__ == '__main__':
    test_function()

运行测试

(venv) PS C:\tmp\test_imports> python .\myproject\tests\test_one.py
I am the return value from api.api!

*查看setuptools文档获取更多详细的setup.py示例。

**在现实中,您可以将虚拟环境放在硬盘上的任何地方。

项目

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