我运行的是Python 2.5。

这是我的文件夹树:

ptdraft/
  nib.py
  simulations/
    life/
      life.py

(我在每个文件夹中都有__init__.py,为了可读性,这里省略了)

我如何从生命模块内导入nib模块?我希望不需要修改sys.path就可以做到。

注意:正在运行的主模块在ptdraft文件夹中。


当前回答

关于从兄弟包导入的问题,我也发表了类似的回答。你可以在这里看到。

不使用sys.解决方案。路径黑客

总结

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

设置

我假设与问题中的文件夹结构相同

.
└── ptdraft
    ├── __init__.py
    ├── nib.py
    └── simulations
        ├── __init__.py
        └── life
            ├── __init__.py
            └── life.py

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

步骤

在根文件夹中添加一个setup.py文件 -- py的内容可以很简单

    from setuptools import setup, find_packages

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

基本上“任何”setup.py都可以工作。这只是一个最小的工作示例。

使用虚拟环境


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

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

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

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

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

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

导入预挂主文件夹到每次导入


在本例中,主文件夹是ptdraft。这样做的好处是,你不会遇到与其他模块名称(来自python标准库或第三方模块)的名称冲突。


示例使用

nib.py

def function_from_nib():
    print('I am the return value from function_from_nib!')

life.py

from ptdraft.nib import function_from_nib

if __name__ == '__main__':
    function_from_nib()

运行life.py

(venv) PS C:\tmp\test_imports> python .\ptdraft\simulations\life\life.py
I am the return value from function_from_nib!

其他回答

我们的文件夹结构:

/myproject
  project_using_ptdraft/
    main.py
  ptdraft/
    __init__.py
    nib.py
    simulations/
      __init__.py
      life/
        __init__.py
        life.py

我理解这一点的方式是以包为中心的观点。 包根是ptdraft,因为它是包含__init__.py的最顶层

例如,包中的所有文件都可以使用绝对路径(相对于包根)进行导入 在life.py中,我们简单地有:

import ptdraft.nib

然而,为了包开发/测试目的而运行life.py,而不是python life.py,我们需要使用:

cd /myproject
python -m ptdraft.simulations.life.life

注意,在这一点上,我们根本不需要修改任何路径。


更令人困惑的是,当我们完成ptdraft包时,我们想在一个驱动程序脚本中使用它,它必须在ptdraft包文件夹之外,也就是project_using_ptdraft/main.py,我们需要摆弄路径:

import sys
sys.path.append("/myproject")  # folder that contains ptdraft
import ptdraft
import ptdraft.simulations

使用python main.py运行脚本没有问题。

有用的链接:

https://tenthousandmeters.com/blog/python-behind-the-scenes-11-how-the-python-import-system-works/(查看如何使用__init__.py) https://chrisyeh96.github.io/2017/08/08/definitive-guide-python-imports.html#running-package-initialization-code https://stackoverflow.com/a/50392363/2202107 https://stackoverflow.com/a/27876800/2202107

与过去的答案风格相同,但行数更少:P

import os,sys
parentdir = os.path.dirname(__file__)
sys.path.insert(0,parentdir)

文件返回您正在工作的位置

相对进口(如从..Import mymodule)只在包中工作。 导入当前模块父目录中的'mymodule':

import os
import sys
import inspect

currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
parentdir = os.path.dirname(currentdir)
sys.path.insert(0, parentdir) 

import mymodule

编辑:__file__属性并不总是给定的。我现在建议使用inspect模块来检索当前文件的文件名(和路径),而不是使用os.path.abspath(__file__)

导入系统 sys.path.append(“. . /”)

我有一个专门针对git存储库的解决方案。

首先,我使用sys.path.append('..')和类似的解决方案。如果你导入的文件本身使用sys.path.append('..')导入文件,这会导致特别的问题。

然后我决定总是附加git存储库的根目录。在一行中是这样的:

sys.path.append(git.Repo('.', search_parent_directories=True).working_tree_dir)

或者更详细一点,像这样:

import os
import sys
import git
def get_main_git_root(path):
    main_repo_root_dir = git.Repo(path, search_parent_directories=True).working_tree_dir
    return main_repo_root_dir
main_repo_root_dir = get_main_git_root('.')
sys.path.append(main_repo_root_dir)

对于最初的问题:根据存储库的根目录,导入将是

import ptdraft.nib

or

import nib