如何使 python 文件相对和绝对可导入?我得到 ModuleNotFoundError 或 ImportError

How to make python file importable relatively and absolutely? I get either ModuleNotFoundError or ImportError

我有以下 python 代码结构:

.
├── my_main.py
└── my_pkg
    ├── my_dep.py
    ├── my_script.py

my_main.pymy_script.py 都应该是可调用的(有一个 if __name__ == '__main__')部分:

my_main.py:

import my_pkg.my_script 
if __name__ == '__main__':
    print(my_pkg.my_script.bar())

my_script.py:

import my_dep
def bar():
    return my_dep.foo() + 1
if __name__ == '__main__':
    print(bar())

这导入... my_dep.py:,看起来像:

def foo():
    return 1

如果你想一起看,看这里:https://github.com/ct2034/python_import_trouble

问题:

我怎样才能使它们都起作用?

注意:这是在 Python 3.8

抱歉冗长的解释。无法使它更简洁。希望可以理解。

设置您的代码以使用像 from my_pkg import my_dep 这样的绝对导入。然后你可以 运行 这样的脚本:

  • my_main.py可以直接执行
  • my_script.py可以用python -m mypkg.my_script
  • 执行

如果这意味着成为一个可安装的包,您可以使用 setup.py 创建入口点或脚本,它们将被安装到某个系统范围内可访问的 bin 目录中。

Both my_main.py and my_script.py should be callable (have a if name == 'main') section)

不,他们不应该。

你想做的是一个非 Pythonic 的设计,即使你通过一些工作设法实现了它,你以后也会被咬住。后者更糟,因为它可能破坏更多东西,包括生产代码。

我强烈建议您遵守通用规则:

  • 只有在 sys.path
  • 中才能找到模块
  • 相对导入只在包中有意义
  • 包中的模块永远不应作为脚本调用

它确实会迫使您调整您的设计,但它会顺利运行并且可以很容易地打包成一个发行版。

如果您有多个相关模块,我的建议是将其设计为一个包(包含 __init__.py 个文件)。然后您将获得自然的相对进口。

如果您额外需要启动脚本,您可以使用包模块构建 wrapper 脚本或使用顶级包文件夹中的 __main__.py 文件:它如果你的 运行 python -m package 将被执行。但是,请不要尝试 运行 有时将同一文件作为包模块,有时将其作为脚本。或者至少不要指望我在这方面帮助你...

我找到了让它工作的方法。 Serge 完全正确地说这应该完全不同 ()。 但如果你仍然想要它,这是如何做到的:

my_script.py:

if __name__ != '__main__':
    from . import my_dep
def bar():
    return my_dep.foo() + 1
if __name__ == '__main__':
    import my_dep
    print(bar())

也在这里.. https://github.com/ct2034/python_import_trouble/tree/bad_solution