为什么在导入的模块中导入的工作方式不同



如果我有

a.py
b.py

b.py中,我可以import a

但如果我有

c.py
m
a.py
b.py

c.py中做import m.b,突然在b.py中得到ModuleNotFoundError: No module named 'a'

怎么了?我看不出第二种情况与第一种有什么不同

所以。。。在最初启动的模块的目录中搜索模块。我就是不明白其中的道理。

我不是在问如何解决这个问题。但与其说是问为什么一开始就有问题。。。

(在Python 3.8.8上测试(

它基于运行python的文件。

如果使用python c.py运行

文件c.py使用:

from m import a, b

文件b.py也使用:

from m import a

如果你使用python b.py,你只需要import a就可以在b.py 中使用

因此,根据您运行的文件,它将是相对导入的父文件。

让我们从第一个工作原理开始。假设您有这样的文件结构:

c.py
m - |
|
__init__.py
a.py
b.py

假设您当前的目录在m文件夹中,并且您运行了该命令。

python b.py

如果在您的b.py中放置以下内容:

import a
import sys
print(sys.path)

它会很好用的。但让我们来看看print(sys.path)的输出。在windows上,这看起来像['C:\path\to\myprogram\m', '<path to python installation>', etc.]

重要的是m文件夹在sys.path上,这就是解决import a的方法。

然而,如果我们上升一个级别并运行:

python c.py

您应该立即注意到m不再在您的sys.path上,而是由'C:\path\to\myprogram'替换。

这就是它失败的原因。Python会自动将您当前的工作目录包含在sys.path中,更改它意味着它不再知道在哪里查找导入。

这是一个绝对重要的例子。您可以通过修改sys.path以包含要导入的文件的路径来操作python查找这些导入的位置。

sys.path.append('C:\path\to\myprogram\m')

但有一个更好的方法。如果m是一个包或子包(包括一个__init__.py(,则可以使用相对导入。

from . import a

然而,有一个小小的警告。只有当使用相对导入的文件作为模块或包运行时,才能使用相对导入。

因此,将它们直接作为顶级脚本运行

python b.py

将产生

ImportError: attempted relative import with no known parent package

幸运的是,Python能够将脚本作为内置模块运行。如果您将cd提升一级以便封装您的m包,则可以运行

python -m m.b

让它运行得很好。

此外,由于importb.py被视为c.py中的一个模块,因此在这种情况下,相对导入也会起作用。

python c.py

最新更新