兄弟姐妹包import

我已经尝试阅读兄弟import甚至包文档的问题 ,但我还没有find答案。

具有以下结构:

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

正如其他地方已经提到的,可怕的事实是,你必须做丑陋的黑客,以允许从__main__模块的兄弟模块或父母包import。 这个问题在PEP 366中有详细描述。 PEP 3122试图以一种更合理的方式处理import,但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 

这里path[0]是你的运行脚本的父文件夹, dir(path[0])你的顶级文件夹。

尽pipe如此,我仍然无法使用相对导入,但它确实允许从顶层(在您的示例api的父文件夹)的绝对导入。

下面是另一个替代scheme,我将其插入到tests文件夹中的Python文件的顶部:

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

你不需要,也不应该破解sys.path除非有必要,在这种情况下,它不是。 使用:

 import api.api_key # in tests, examples 

从项目目录运行: python -m tests.test_one

你可能应该在api里面移动tests (如果是api的unittests)并运行python -m api.test来运行所有的testing(假设有__main__.py )或者python -m api.test.test_one来运行test_one

你也可以从examples删除__init__.py (它不是一个Python包),并在安装api的virtualenv中运行例子,例如pip install -e . 在virtualenv会安装就地api包,如果你有适当的setup.py

我还没有理解Pythonology的必要性,以查看在无关联项目之间共享代码的预期方式,而不需要兄弟/相对导入攻击。 直到那一天,这是我的解决scheme。 对于从..\api导入内容的examplestests ,它看起来像:

 import sys.path import os.path # Import from sibling directory ..\api sys.path.append(os.path.dirname(os.path.abspath(__file__)) + "/..") import api.api import api.api_key 

对于同级软件包导入,可以使用[sys.path] [2]模块的insertappend方法:

 if __name__ == '__main__' and if __package__ is None: import sys from os import path sys.path.append( path.dirname( path.dirname( path.abspath(__file__) ) ) ) import api 

如果你启动你的脚本,这将工作如下:

 python examples/example_one.py python tests/test_one.py 

另一方面,你也可以使用相对导入:

 if __name__ == '__main__' and if __package__ is not None: import ..api.api 

在这种情况下,你必须用'-m'参数来启动你的脚本(注意,在这种情况下,你不能给出'.py'的扩展名):

 python -m packageName.examples.example_one python -m packageName.tests.test_one 

当然,你可以混合使用这两种方法,不pipe它如何被调用,你的脚本都可以工作:

 if __name__ == '__main__': if __package__ is None: import sys from os import path sys.path.append( path.dirname( path.dirname( path.abspath(__file__) ) ) ) import api else: import ..api.api 

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

 import api.api 

那么它期望项目的根目录在系统path中。

最简单的方法来支持这个,不用任何黑客(就像你所说的那样)就是从顶级目录运行例子,就像这样:

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

为了防止在Eclipse上使用Pydev,最终可以使用Project-> Properties并在左侧菜单Pydev-PYTHONPATH下设置External Libraries ,从而将兄弟的父path(以及调用模块的父path)添加为外部库文件夹。 然后,你可以从你的兄弟姐妹,例如from sibling import some_class

首先,你应该避免使用与模块本身同名的文件。 它可能会打破其他import。

导入文件时,解释器首先检查当前目录,然后search全局目录。

里面的examplestests你可以调用:

 from ..api import api 
    Interesting Posts