将函数从位于父文件夹中的模块导入脚本

Importing functions from a module located in parent folder to script

我知道导入是一个常见的头痛问题,但 none 其他解决方案对我有用。

我在尝试从脚本的父文件夹中的模块导入函数时收到 ModuleNotFoundError。这是文件夹结构。

cli_script.py:

from python_tools.utils import foo

def bar():
   foo()

if __name__ == "__main__": 
    bar()

utils.py:

def foo():
    return x

def foo2():
    return y

当我点击 'Run' 时,这在 PyCharm 中有效,但是当 运行 从命令行使用 python3 cli_script.py 时,我得到了上述错误。

我也试过 python3 -m cli_script.py 这是同样的错误: ModuleNotFoundError: No module named 'python_tools'

从其他回答中我了解到这与我的sys.path有关。他们大多建议在脚本中以某种方式修改它,但这似乎很老套/非 pythonic。

我们的想法是拥有一个带有一堆函数的模块,然后将这些函数以配方样式导入到一堆工具中,这些工具被隔离到不同的目录中。所有这些工具都将是脚本(如果 _name__ == _main__)。

请告诉我是否有更好的目录结构,或者如果没有 hacky 变通办法就无法实现。

谢谢!

首先,一旦您 pip install 您的包,这个 实际上工作,即使只有用于本地测试的 --editable 选项。因为 Python 解释器将能够在模块搜索路径上找到您的包 python_tools 并从那里获取它。

我不知道似乎正在发生的 PyCharm 魔法。但是,是的,您可以将父文件夹 "manually" 添加到模块搜索路径。例如像这样:

import sys
sys.path.append('..')

通常这样就可以了。如果相对路径 .. 没有削减它,或者看起来太 "hacky",您还可以从 pre-defined __file__ 属性获取脚本的绝对路径并使用来自 os.path or methods from pathlib 的函数(并转换为 str 以便 appendsys.path)。

更好的目录结构可能是将 utils.py 放在与命令行脚本相同的文件夹中,或者放在子文件夹中,作为包中的模块。那是因为解释器直接执行的脚本目录总是在模块搜索路径上。

John 的所有解决方案都有效,我基本上选择了最后一个,但想正式说明我遇到的问题(现在理解得更好)。

Python的sys.path是基于执行上下文构建的。由于我是从不同的目录执行脚本,因此导入是相对于该上下文的。

我通过添加硬编码相对导入解决了这个问题:

import os, sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

到cli_script.py的顶部。这是最便携的解决方案。

一个更优雅的解决方案是 pip install utils.py 所以它总是在 sys.path 并且可以被任何 module/script.

导入

您还可以将 PYTHONPATH 环境变量添加到您的 bash 配置文件中,但我认为该解决方案是最糟糕的。

Chris Yeh 令人难以置信的 write-up 帮助我解决了这个问题,请参阅案例 #4。