我运行的是Python 2.5。

这是我的文件夹树:

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

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

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

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


当前回答

在删除了一些系统路径黑客后,我认为添加它可能是有价值的

我喜欢的解决方案。

注意:这是一个框架挑战-没有必要在代码中做。

假设有一棵树,

project
└── pkg
    └── test.py

test.py包含什么

import sys, json; print(json.dumps(sys.path, indent=2)) 

使用路径执行只包括包目录

python pkg/test.py
[
  "/project/pkg",
 ...
]

但是使用module参数会包含项目目录

python -m pkg.test
[
  "/project",
  ...
]

现在,从项目目录导入的所有内容都可以是绝对的。不需要再耍花招了。

其他回答

在Jupyter笔记本上(用Jupyter LAB或Jupyter Notebook打开)

只要你在木星笔记本上工作,这个简短的解决方案可能会有用:

%cd ..
import nib

即使没有__init__.py文件,它也能工作。

我在Linux和Windows 7上用Anaconda3测试了它。

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

不使用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!

我有一个专门针对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

下面是一个更通用的解决方案,它将父目录包含到sys. conf中。路径(适用于我):

import os.path, sys
sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir))

在我看来,你并不真的需要导入父模块。让我们假设在nib.py中有func1()和data1,你需要在life.py中使用

nib.py

import simulations.life.life as life
def func1():
   pass
data1 = {}
life.share(func1, data1)

life.py

func1 = data1 = None

def share(*args):
   global func1, data1
   func1, data1 = args

现在您可以访问life.py中的func1和data。当然,在尝试使用它们之前,你必须小心地在life.py中填充它们,