如何在多目录项目中正确导入 python 模块?
How do I properly import python modules in a multi directory project?
我有一个 python 项目,其基本设置如下所示:
imptest.py
utils/something.py
utils/other.py
这是脚本中的内容:
imptest.py
#!./venv/bin/python
import utils.something as something
import utils.other as other
def main():
"""
Main function.
"""
something.do_something()
other.do_other()
if __name__ == "__main__":
main()
something.py
#import other
def do_something():
print("I am doing something")
def main():
"""
Main function
"""
do_something()
#other.do_other()
if __name__ == "__main__":
main()
other.py
def do_other():
print("do other thing!")
def main():
"""
Main function
"""
do_other()
if __name__ == "__main__":
main()
imptest.py 是 运行 的主要文件,偶尔会为某些事情调用 utils 函数。
如您所见,我在导入“其他”模块进行测试的“something.py”中注释掉了一些行。
但是当我想测试 something.py 中的某些功能时,我必须 运行 文件 something.py 并取消注释导入行。
这感觉有点笨拙。
如果我离开
import other
未注释和 运行 imptest.py,我收到此错误:
Traceback (most recent call last):
File "imptest.py", line 5, in <module>
import utils.something as something
File "...../projects/imptest/utils/something.py", line 3, in <module>
import other
ModuleNotFoundError: No module named 'other'
执行此操作的更好方法是什么?
您需要在主目录中添加一个 __init__.py
文件,以便 python 知道它是一个包。然后你可以像这样添加一个 import 语句, from .other import function
这里的问题是路径,考虑这个目录结构
main
- utils/something.py
- utils/other.py
imptest.py
当您尝试使用相对路径将 other
导入到 something.py
时,您会执行类似于 from . import other
的操作。这在您执行 $ python something.py
时会起作用,但在您 运行 $ python imptest.py
时会失败,因为在第二种情况下它会搜索 main/other.py 不存在的 [=20] =]
因此,为了解决此问题,我建议您使用 $ python -m
为 something.py & other.py 和 运行 编写单元测试(mod) 命令。 (我强烈推荐这种方法)
但是......如果你真的让你现有的代码在没有太多mod化的情况下工作,那么你可以在something.py中添加这两行文件(这可行,但我不推荐这种方法)
import sys, os
sys.path.append(os.getcwd()) # Adding path to this module folder into sys path
import utils.other as other
def do_something():
print("I am doing something")
def main():
"""
Main function
"""
do_something()
other.do_other()
if __name__ == "__main__":
main()
为了更好地理解,这里有一些参考资料:
PavanSkipo 已使用相对路径 解决了 ImportError
但文件只能通过 python -m utils.something
作为模块调用 - 而 python utils/something.py
将引发错误。 PavanSkipo 提到的使用 sys.path
的解决方法在我看来并不理想 1.
OP 对语句 if __name__=='__main__'
的使用表明这些文件在某些方面应该是直接 运行 - 可能是脚本 2。在这种情况下,我们应该使用绝对导入和 pip install -e .
使用这种方法允许文件 运行 既作为模块又作为脚本。换句话说,以下所有 python utils/something.py
、python -m utils.something
和 import utils.something
都可以正常工作。
添加setup.py
setup.py
imptest.py
utils/something.py
utils/other.py
setup.py
的最低内容
from setuptools import setup, find_packages
setup(name='utils', version='0.1', packages=find_packages())
使用 pip install -e .
在开发模式下安装后,您应该像在 imptest.py
中一样在 utils/something.py
中使用绝对导入
import utils.other
...
1被测试的代码最好能反映出代码的使用状态
2 好的,也许作为入口点 - 但在那种情况下,无论如何它应该作为一个包安装
我想你要找的就是这个。为了能够导入库并将其用作可执行文件,您可以这样做。首先,你应该制作 utils
一个包。这意味着在其中创建 __init__.py
。
内容应该是这样的:
→ cat utils/__init__.py
import os
import sys
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
这将使导入语句在 imptest.py
中作为 from utils import something, other
以及在 something.py
中作为 import other
工作。
最终作品如下:
→ tree
.
|-imptest.py
|-utils
| |-__init__.py
| |-other.py
| |-something.py
→ cat imptest.py
#!./venv/bin/python
from utils import something, other
def main():
"""
Main function.
"""
something.do_something()
other.do_other()
if __name__ == "__main__":
main()
→ cat utils/something.py
import other
def do_something():
print("I am doing something")
def main():
"""
Main function
"""
do_something()
other.do_other()
if __name__ == "__main__":
main()
→ python3 imptest.py
I am doing something
do other thing!
→ python3 utils/something.py
I am doing something
do other thing!
这个技巧使两个导入语句都有效。它基本上将 utils
目录路径添加到搜索路径中,无论它位于何处。因此,import other
将起作用。 __init__.py
使 utils
目录成为 package;
我有一个 python 项目,其基本设置如下所示:
imptest.py
utils/something.py
utils/other.py
这是脚本中的内容:
imptest.py
#!./venv/bin/python
import utils.something as something
import utils.other as other
def main():
"""
Main function.
"""
something.do_something()
other.do_other()
if __name__ == "__main__":
main()
something.py
#import other
def do_something():
print("I am doing something")
def main():
"""
Main function
"""
do_something()
#other.do_other()
if __name__ == "__main__":
main()
other.py
def do_other():
print("do other thing!")
def main():
"""
Main function
"""
do_other()
if __name__ == "__main__":
main()
imptest.py 是 运行 的主要文件,偶尔会为某些事情调用 utils 函数。
如您所见,我在导入“其他”模块进行测试的“something.py”中注释掉了一些行。
但是当我想测试 something.py 中的某些功能时,我必须 运行 文件 something.py 并取消注释导入行。
这感觉有点笨拙。
如果我离开
import other
未注释和 运行 imptest.py,我收到此错误:
Traceback (most recent call last):
File "imptest.py", line 5, in <module>
import utils.something as something
File "...../projects/imptest/utils/something.py", line 3, in <module>
import other
ModuleNotFoundError: No module named 'other'
执行此操作的更好方法是什么?
您需要在主目录中添加一个 __init__.py
文件,以便 python 知道它是一个包。然后你可以像这样添加一个 import 语句, from .other import function
这里的问题是路径,考虑这个目录结构
main
- utils/something.py
- utils/other.py
imptest.py
当您尝试使用相对路径将 other
导入到 something.py
时,您会执行类似于 from . import other
的操作。这在您执行 $ python something.py
时会起作用,但在您 运行 $ python imptest.py
时会失败,因为在第二种情况下它会搜索 main/other.py 不存在的 [=20] =]
因此,为了解决此问题,我建议您使用 $ python -m
为 something.py & other.py 和 运行 编写单元测试(mod) 命令。 (我强烈推荐这种方法)
但是......如果你真的让你现有的代码在没有太多mod化的情况下工作,那么你可以在something.py中添加这两行文件(这可行,但我不推荐这种方法)
import sys, os
sys.path.append(os.getcwd()) # Adding path to this module folder into sys path
import utils.other as other
def do_something():
print("I am doing something")
def main():
"""
Main function
"""
do_something()
other.do_other()
if __name__ == "__main__":
main()
为了更好地理解,这里有一些参考资料:
PavanSkipo 已使用相对路径 ImportError
但文件只能通过 python -m utils.something
作为模块调用 - 而 python utils/something.py
将引发错误。 PavanSkipo 提到的使用 sys.path
的解决方法在我看来并不理想 1.
OP 对语句 if __name__=='__main__'
的使用表明这些文件在某些方面应该是直接 运行 - 可能是脚本 2。在这种情况下,我们应该使用绝对导入和 pip install -e .
使用这种方法允许文件 运行 既作为模块又作为脚本。换句话说,以下所有 python utils/something.py
、python -m utils.something
和 import utils.something
都可以正常工作。
添加setup.py
setup.py
imptest.py
utils/something.py
utils/other.py
setup.py
from setuptools import setup, find_packages
setup(name='utils', version='0.1', packages=find_packages())
使用 pip install -e .
在开发模式下安装后,您应该像在 imptest.py
utils/something.py
中使用绝对导入
import utils.other
...
1被测试的代码最好能反映出代码的使用状态
2 好的,也许作为入口点 - 但在那种情况下,无论如何它应该作为一个包安装
我想你要找的就是这个。为了能够导入库并将其用作可执行文件,您可以这样做。首先,你应该制作 utils
一个包。这意味着在其中创建 __init__.py
。
内容应该是这样的:
→ cat utils/__init__.py
import os
import sys
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
这将使导入语句在 imptest.py
中作为 from utils import something, other
以及在 something.py
中作为 import other
工作。
最终作品如下:
→ tree
.
|-imptest.py
|-utils
| |-__init__.py
| |-other.py
| |-something.py
→ cat imptest.py
#!./venv/bin/python
from utils import something, other
def main():
"""
Main function.
"""
something.do_something()
other.do_other()
if __name__ == "__main__":
main()
→ cat utils/something.py
import other
def do_something():
print("I am doing something")
def main():
"""
Main function
"""
do_something()
other.do_other()
if __name__ == "__main__":
main()
→ python3 imptest.py
I am doing something
do other thing!
→ python3 utils/something.py
I am doing something
do other thing!
这个技巧使两个导入语句都有效。它基本上将 utils
目录路径添加到搜索路径中,无论它位于何处。因此,import other
将起作用。 __init__.py
使 utils
目录成为 package;