如何使 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.py
和 my_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
问题:
如果我运行my_script.py
,一切正常。
但是如果我 运行 my_main.py
,我得到:
ModuleNotFoundError: No module named 'my_dep'
如果我将 my_script.py
中的导入更改为 from . import my_dep
,my_main.py
有效。
但是当我 运行 my_script.py
时,我得到:
ImportError: attempted relative import with no known parent package
我怎样才能使它们都起作用?
注意:这是在 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
我有以下 python 代码结构:
.
├── my_main.py
└── my_pkg
├── my_dep.py
├── my_script.py
my_main.py
和 my_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
问题:
如果我运行
my_script.py
,一切正常。但是如果我 运行
my_main.py
,我得到:ModuleNotFoundError: No module named 'my_dep'
如果我将
my_script.py
中的导入更改为from . import my_dep
,my_main.py
有效。但是当我 运行
my_script.py
时,我得到:ImportError: attempted relative import with no known parent package
我怎样才能使它们都起作用?
注意:这是在 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