python - 兄弟包导入

标签 python package python-import siblings

我尝试阅读有关同级导入的问题,甚至 package documentation ,但我还没有找到答案。

结构如下:

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

examplestests 目录下的脚本如何从 api 模块并从命令行运行?

另外,我想避免对每个文件进行丑陋的 sys.path.insert hack。一定 这可以在 Python 中完成,对吧?

最佳答案

厌倦了 sys.path hack?

有很多sys.path.append -hacks 可用,但我找到了解决手头问题的替代方法。

总结

  • 将代码打包到一个文件夹中(例如 packaged_stuff)
  • 创建 setup.py您使用的脚本setuptools.setup() . (请参阅下面的最小 setup.py)
  • 使用 pip install -e <myproject_folder> 将包安装到可编辑状态
  • 使用 from packaged_stuff.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 import function_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

步骤

  1. 将 setup.py 文件添加到根目录

setup.py 的内容会是*

from setuptools import setup, find_packages

setup(name='myproject', version='1.0', packages=find_packages())
  1. 使用虚拟环境

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

  • 创建虚拟环境
    • python -m venv venv
  • 激活虚拟环境
    • source ./venv/bin/activate (Linux, macOS) 或 ./venv/Scripts/activate (赢)

要了解更多信息,只需谷歌搜索“python 虚拟环境教程”或类似内容。除了创建、激活和停用之外,您可能永远不需要任何其他命令。

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

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]
  1. 以可编辑状态 pip 安装您的项目

安装您的顶级软件包myproject使用 pip .诀窍是使用 -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
  1. 添加 myproject.进入你的进口

请注意,您必须添加 myproject.仅适用于否则无法正常工作的进口。不使用 setup.py 的导入& pip install仍然可以正常工作。请参阅下面的示例。


测试解决方案

现在,让我们使用 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 docs获取更详细的 setup.py 示例。

** 实际上,您可以将虚拟环境放在硬盘上的任何位置。

关于python - 兄弟包导入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6323860/

相关文章:

python - 存储用户移动位置的最佳数据库,优先考虑读写速度?

python - Numpy uint8_t 数组到 vtkImageData

java - 简单的导入问题

delphi - 从类引用创建的表单中执行方法 (Delphi)

python - 如何pip安装本地python包?

使用nose进行测试的Python导入-在当前包之上导入模块的最佳实践是什么

python - 如何在 Heroku 上使用 Mechanize、BeautifulSoup、html2text

python - 如果您有数字间隔,请计算分组中位数

matlab - 为什么在函数中使用其内容后*可以导入包?

python - 为什么 "import *"不好?