在Python中从相邻文件夹导入模块

5

我想问一下,是否有一种方法可以从项目中相邻的文件夹中导入模块/函数。

例如,假设我有两个文件:

project/src/training.py
project/lib/functions.py

现在这两个文件夹都有__init__.py文件。如果我想要在training.py中导入functions.py,看起来它不能被检测到。我试着使用from lib.functions import *。我知道这可以从文件夹结构的上层调用两个文件,但是是否有一种方法可以在上面/旁边的文件夹中执行它?

这个问题不一致。这些是文件,而不是文件夹。初始化文件是__init__.py,而不是__init.py__。你可以使用import functions从另一个模块导入一个模块。请创建一个最小化、完整化和可验证的示例 - zvone
如果外层文件夹 project 中有一个 __init__.py 文件,则可以使用相对导入:from ..lib import functions,或者 from ..lib.functions import * 或其他类似方式。 - Green Cloak Guy
抱歉,之前有些打字错误。现在这样是否更清晰明了? - mlenthusiast
@GreenCloakGuy似乎不起作用。 - mlenthusiast
这个主题有很多问题:https://dev59.com/GW855IYBdhLWcg3wXTEI,https://dev59.com/2WQn5IYBdhLWcg3wP1JT,https://dev59.com/QXE95IYBdhLWcg3wWMhQ,https://dev59.com/0XVC5IYBdhLWcg3wfhGL,https://dev59.com/y3VD5IYBdhLWcg3wJIAK。但是,值得承认的是,大多数排名前几位的解决方案都是非常糟糕的建议。 - jpmc26
3个回答

8

基本上,最佳方法取决于这两个模块的关系。有两种情况:

  1. 这两个模块是一个整体的一部分,旨在作为一个整体使用,而不是作为独立的部分。 (这是最常见的情况,如果您不确定,应该选择这种方式。)
  2. functions.py模块是training.py的依赖模块,但是可以单独使用。

整体一体

如果这些模块是一个整体的一部分,那么这不是Python项目中结构化的标准方式。

如果您需要在同一项目中使用多个模块,则标准的文件夹结构方式是将所有模块放在单个中,如下所示:

project/
    trainingproject/
        __init__.py
        training.py
        functions.py
    other/
        ...
    project/
        ...
    folders/
        ...

__init__.py 文件会让 Python 将 trainproject/ 目录识别为一个叫做包的单元。使用包可以启用相对导入功能:

training.py

from . import functions

# The rest of training.py code

假设您当前的目录是project,则可以将training.py作为模块调用:
python -m trainingproject.training

分离单元

如果您的模块实际上是单独的包,那么在开发过程中最简单的惯用解决方案是修改PYTHONPATH环境变量:

使用sh衍生语法:

# All the extra PYTHONPATH references on the right are to append if it already has values
# Using $PWD ensures that the path in the environment variable is absolute.
PYTHONPATH=$PYTHONPATH${PYTHONPATH:+:}$PWD/lib/
python ./src/training.py

PowerShell 语法:

$env:PYTHONPATH =  $(if($env:PYTHONPATH) {$env:PYTHONPATH + ';'}) + (Resolve-Path ./lib)
python ./src/training.py

(这在命令提示符中也可以实现,但我将其省略,因为PowerShell更受欢迎。)
在您的模块中,您只需执行正常的导入语句:
training.py
import functions

# Rest of training.py code

这样做将会在您将代码部署到生产环境时起作用,如果您复制所有文件并设置正确的路径,但是您可能需要考虑把functions.py打包成一个wheel文件,然后使用pip进行安装。这将消除通过将functions.py安装到site-packages来设置PYTHONPATH的需要,这将使import语句可以直接使用。这也将使得更容易分发functions.py以便与其他脚本独立使用,而不必依赖于training.py。我不会在这里介绍如何创建wheel文件,因为它超出了这个问题的范围,但这里有一个简介

谢谢!这正是我在寻找的,感谢你提供了全面的答案。我想我必须走Python的路线,因为它们是独立的模块。我知道如何将紧密的单元打包,但这绝对涵盖了所有方面。 - mlenthusiast
针对单独的单元,创建一个 setup.py 文件并运行 pip install -e 命令效果良好。 - Brent

1

是的,它就像从工作目录编写整个路径一样简单:

from project.src.training import *

或者

from project.lib.functions import *

这就是问题所在,当我使用这个方法时,它告诉我顶层文件夹不是一个模块,在这种情况下是'project'。 - mlenthusiast
1
如果您在顶层文件夹中放置一个__init__.py文件,那么它应该可以正常工作。 - Green Cloak Guy
4
对我来说,“project”仍然不是一个包。 - Morten Nissov

0

我同意 polymath 上面所说的。如果你也想知道如何在导入这些特定脚本或函数后运行它们,可以使用:your_function_name(parameters)。要运行从同一目录中导入的脚本等,请使用:exec('script_name.py')。然而,我建议制作函数而不是使用 exec 命令,因为它可能有点难以正确使用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接