Python 无法从包中导入模块。

3

我有一个flask restful项目,其文件布局如下(为方便更改了文件名)

myproject/
    __init__.py
    app.py
    common/
        __init__.py
        util.py
    foo/
        __init__.py
        main.py
        utilities.py

foo/ 只是一个包含 API 端点代码的文件夹,我计划在未来添加其他端点,因此我有一个 common/util.py 文件,其中包含可重用的函数,我将在其他 API 端点中使用。

foo/main.py

from flask_restful import Resource, request

from utilities import Analysis

class Foo(Resource):
    def get(self):      
        pass

foo/utilities.py 中,我有一些带有方法的类来获取一些数据,我将这些类导入到 foo/main.py 中以返回JSON响应。

foo/utilities.py 中的类还使用了来自 common/util.py 的一些函数,但是当我尝试从 common/util.py 中导入一些东西到 foo/utilities.py 时,我会得到一个错误:import common.util ModuleNotFoundError: No module named 'common'

这是什么原因?我尝试过不同的导入方式:

from common.util import my_func from .common.util import my_func from myproject.common.util import my_func

但都没有成功。

如果有影响的话,这是 myproject/app.py:

from flask import Flask
from flask_restful import Api

from foo.main import Foo

app = Flask(__name__)
api = Api(app)

api.add_resource(Foo, '/Foo')

if __name__ == "__main__":
    app.run()

如果有影响的话,我正在激活的虚拟环境中完成所有操作。


Python的哪个版本?Py2和Py3对于隐式相对导入有不同的规则。 - phd
@phd 我正在使用Python 3。 - gigamarr
你已经安装了 myproject 吗?还是直接作为脚本运行 foo/main 而没有进行安装?如果是后者,那么 myprojectsys.path 中不可用,只有目录 foo,并且它不是一个包,所以你不能使用相对导入。 - phd
安装是什么意思?我不运行 foo/main.py,我运行 myproject/app.py 来运行整个 API,它可以正常运行,但在 foo/utilities.py 中导入 common.util 失败,为了测试它,我运行 foo/utilities.py,然后得到上面写的错误。 - gigamarr
通过运行python setup.py installpip install,将myproject的副本放置到当前Python(或已经在sys.path中的任何目录)的site-packages/目录中。当然,你必须拥有setup.py文件。 - phd
1个回答

3

从common.util导入my_func

在Python 3中,这是绝对导入,也就是说,具有子目录“common /”的目录必须在“sys.path”中。在您的情况下,这肯定是错误的方法。

从.common.util导入my_func

此导入要求“common”是“foo”的子目录,但实际情况并非如此。

从myproject.common.util导入my_func

这最终是最好的方法,但为使其起作用,“myproject /”子目录的父目录必须在“sys.path”中。您可以安装整个“myproject”,或将父目录添加到“$ PYTHONPATH”环境变量中,或将该目录添加到“foo / main.py”的“sys.path”中。类似于:

PYTHONPATH=/home/to/parentdir /home/to/parentdir/myproject/foo/main.py

或者

import sys
sys.path.insert(0, '/home/to/parentdir')

/home/to/parentdirmyproject/ 目录所在的目录。

安装完 myproject 或将其上级目录添加到 sys.path 后,您也可以使用相对导入。请记住,与 foo 相比,common 是一个同级包,因此导入不能使用 .common ,而应该使用 ..common

from ..common.util import my_func

谢谢,它起作用了。在 myproject/app.py 的顶部添加了以下内容: import sys sys.path.insert('path/to/parent/of/myproject') 一切都很好。唯一的问题是,在 foo/utilities.py 中我必须使用绝对导入,例如 from myproject.common.util import,但暂时可以这样做。 - gigamarr
1
sys.path.insert(0, 'path/to/parent') not sys.path.insert('path/to/parent') - gigamarr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接