【问题标题】:Python Submodule Importing MadnessPython 子模块导入疯狂
【发布时间】:2023-04-08 08:10:01
【问题描述】:

我正在通过一些基本的 Python 导入将我的头撞到墙上。我已经尽可能地简化了这个问题,希望如果我了解它是如何工作的,我能够将它扩展到更大的范围

这是两难境地 -
run.py 子模块内部的 p1 有效,但在顶层时无效。为什么?

(版本 Python 3.6.3)


结构:

/sandbox
    __init__.py
    /p1
        __init__.py
        file1.py
        run.py
    run.py

/sandbox/p1/__init__.py

__all__ = ["file1", "file2"]

/sandbox/p1/file1.py

from file2 import B
class A(object):
    pass

/sandbox/p1/file2.py

class B(object):
    pass

/sandbox/p1/run.py

from file1 import A
a = A()

/sandbox/run.py

from p1 import file1
a = file1.A()

在做:

python p1/run.py(工作正常)
python run.py

Traceback(最近一次调用最后一次): 文件“run.py”,第 2 行,在 从 p1 导入文件 1 文件“.../sandbox/p1/file1.py”,第 1 行,在 从文件 2 导入 B ModuleNotFoundError: 没有名为“file2”的模块

【问题讨论】:

  • 这个模块是否在你的 python(环境?)路径中的某个地方?如果不是,您需要进行相对导入from .p1 import file1。如果是,可以使用from sandbox.p1 import file1 导入
  • from p1 import file1 -> 这一行找到 file1 并尝试导入它。但是 file1 无法导入 file2 虽然它在同一路径中
  • file1 应该有 from .file2 import B 出于同样的原因
  • 谢谢。刚试过这个,有趣的事情发生了。顶部模块中的 run.py 有效,但 p1/run.py 无效。回溯(最后一次调用):文件“p1/run.py”,第 1 行,在 from file1 import A File “/Users/bogdan.culda/Desktop/workspace/sandbox/p1/file1.py”,第 1 行,在 from .file2 import B ImportError: 尝试相对导入,没有已知的父包

标签: python import git-submodules


【解决方案1】:

(I) 没有名为'file2'的模块

你遇到No module named 'file2'是因为你在一个包外运行run.py,当file1 import file2,python找不到file2作为模块目录不在模块搜索路径中。

对于您的场景,file1file2 是 2 个模块,它们在同一个包中,对于这种情况,建议您使用 relative import,这是最佳做法。

file1.py

from .file2 import B
class A(object):
    pass

然后,python run.py 工作。

(II) 尝试在没有已知父包的情况下进行相对导入

正如你提到的,如果执行python p1/run.py,你将看到接下来的内容:

尝试在没有已知父包的情况下进行相对导入

什么意思?

这是因为 relative import 只能在包中的模块中支持。

您可能会说file1.py 在包p1 中,为什么仍然看到错误?

这是因为python使用__name__来判断这个模块是否在包中,而不是通过它的位置。

file1.py改成如下:

print(__name__)
from .file2 import B
class A(object):
    pass

接下来是输出:

python run.py

p1.file1

python p1/run.py

文件1

对于python p1/run.py,因为它在包中运行,python会不知道它在包中,所以输出为file1

如果__name__没有.,python会认为它不在包中,所以相对导入失败。

(III) 最后,如果你真的想执行python p1/run.py,例如:对你的包进行单元测试?

使用python -m p1.run,这应该可以执行包内的顶级脚本。

【讨论】:

  • 您对 Python 2 和 Python 3 区别的描述不正确。 Python 2 和 Python 3 都将脚本的目录添加到模块搜索路径中;不同之处在于 Python 2 具有隐式相对导入。
  • 我的意思是模块的当前目录,而不是顶级脚本的目录。
  • 如果我们不使用relative import,如何理解OP的原始错误? Python2可以,但是python3会报错吗?请教我,谢谢。
  • Python 2 不会将模块的目录添加到sys.path。发生的情况是,当p1.file1 模块执行from file2 import B 时,Python 2 将首先尝试将其解释为from p1.file2 import B,并且如果找不到p1.file2,它只会寻找顶级file2 模块。
  • 是的,你是对的,去掉py2/py3的区别,谢谢教我。
【解决方案2】:

Python 故意使在模块中混合脚本变得困难。可以这样处理的方式是这样的:

/project
    /scripts
        run.py
    /sandbox
        __init__.py
        /p1
            __init__.py
            file1.py
            file2.py

/project/sandbox/p1/file1.py

from .file2 import B
class A(object):
    pass

/project/sandbox/p1/file2.py

class B(object):
    pass

/project/scripts/run.py

from sandbox.p1.file1 import A
a = A()

我确保/project 的路径位于我想从中使用它的虚拟环境的站点包中的.pth 文件中。

康达

如果你使用conda,你可以使用conda develop

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-02-05
    • 2015-03-25
    • 2011-12-22
    • 1970-01-01
    • 2013-07-30
    • 1970-01-01
    • 1970-01-01
    • 2010-12-12
    相关资源
    最近更新 更多