如何在多目录项目中正确导入python模块?

2024-09-30 01:24:09 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个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()

什么,派克

#import other

def do_something():
    print("I am doing something")


def main():
    """
    Main function
    """

    do_something()
    #other.do_other()

if __name__ == "__main__":
    main()

其他的

def do_other():
    print("do other thing!")

def main():
    """
    Main function
    """

    do_other()

if __name__ == "__main__":
    main()

py是主文件,它偶尔会运行和调用utils函数

正如你们所看到的,我已经注释掉了“something.py”中的一些行,在这里我导入了“other”模块进行测试

但是,当我想在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'

有什么更好的方法


Tags: namepyimportifmaindefasfunction
3条回答

这里的问题是路径,考虑这个目录结构

main
 - utils/something.py
 - utils/other.py
 imptest.py

当您尝试使用中的相对路径导入othersomething.py时,您将执行类似from . import other的操作。当您执行$ python something.py时,这将起作用,但当您运行$ python imptest.py时,这将失败,因为在第二个场景中,它搜索不存在的main/other.py

因此,为了解决这个问题,我建议您为something.py&;编写单元测试;other.py并使用$ python -m(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()

以下是一些参考资料,以便更好地理解:

我想你要找的是这个。为了能够导入库并将其用作可执行文件,您可以这样做。首先,您应该使utils成为一个包。这意味着在其内部创建__init__.py

它的内容应该是:

→ cat utils/__init__.py
import os
import sys
sys.path.append(os.path.dirname(os.path.realpath(__file__)))

这将使import语句作为imptest.py中的from utils import something, othersomething.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

PavanSkipo已使用相对路径here解决了ImportError问题,但文件只能通过python -m utils.something作为模块调用,而python utils/something.py将抛出错误。在我看来,使用sys.path的解决方法(如PavanSkipo在中所述)并不理想

OP在__name__=='__main__'中使用的语句表明文件是以某种方式直接运行的,可能是作为脚本2。在这种情况下,我们应该使用绝对导入和pip install -e .

使用这种方法,文件可以作为模块和脚本单独运行。换句话说,下面所有的python utils/something.pypython -m utils.somethingimport 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可以作为入口点,但在这种情况下,它应该作为软件包安装

相关问题 更多 >

    热门问题