为啥“导入模块”然后“从包导入模块”再次加载模块?

Posted

技术标签:

【中文标题】为啥“导入模块”然后“从包导入模块”再次加载模块?【英文标题】:Why does "import module" and then "from package import module" load the module again?为什么“导入模块”然后“从包导入模块”再次加载模块? 【发布时间】:2011-09-11 01:28:05 【问题描述】:

我的 PYTHONPATH 中有一个包,看起来像这样:

package/
    __init__.py
    module.py
        print 'Loading module'

如果我从 package/ 目录运行 Python(或在此目录中编写另一个模块)并键入

import module

它加载 module.py 并按预期打印出“加载模块”。但是,如果我再输入

from package import module

它加载 module.py 并打印“加载模块”再次,这是我没想到的。这是什么原理?

注意:我想我从技术上理解 Python 这样做的原因,因为 import module 的 sys.modules 键只是 "module",但对于 from package import module,它是 "package.module"。所以我想我想知道的是为什么这里的键不同——为什么不将文件的路径名用作键,以便 Python 在这里做人们所期望的?

【问题讨论】:

想想只使用文件名意味着什么:这意味着两个包不能包含同名文件,因为第二次导入会给出第一个导入的文件! @delnam,是的,虽然我的意思是“完整路径名”——编辑问题以澄清。 如果您不想再次导入,为什么不直接使用module = package.module @Wooble,是的,我知道在这种特殊情况下如何解决它,这只是我的问题的一个例子。我想知道的是我所描述的行为的基本原理。 您是指import package 还是import package.module?因为这可能会有所作为。 【参考方案1】:

实际上,通过运行 package 目录中的代码,您错误地配置了 Python。你不应该把那个目录放在sys.path,因为它在一个包里面。

Python 不使用文件名作为键,因为它不是在导入文件,而是在导入模块。允许人们做“import c:\jim\my files\projects\code\stuff”会助长各种肮脏行为。

请考虑这种情况:如果您在 ~/foo/package/~/barPYTHONPATH - 但 ~/bar 只是到 ~/foo 的符号链接怎么办?您是否希望 Python 能够解析,然后为您删除重复的符号链接?如果您在 PYTHONPATH 上放置一个相对目录,然后更改目录怎么办?如果 'foo.py' 是 'bar.py' 的符号链接怎么办?您是否希望这两个也都被重复数据删除?如果它们不是符号链接,而只是精确的副本怎么办?添加复杂的规则来尝试在模棱两可的情况下做一些方便的事情意味着它会做一些对其他人非常不方便的事情。 (Python zen 12:面对歧义,拒绝猜测的诱惑。)

Python 在这里做了一些简单的事情,确保环境设置正确是您的责任。现在,您可能会争辩说,默认情况下将当前目录放在PYTHONPATH 上并不是一个好主意——我什至可能同意你的观点——但鉴于它在那里,它应该遵循与其他路径相同的一致规则集条目做。如果它打算从任意目录运行,您的应用程序始终可以从sys.path 中删除当前目录,方法是从sys.path.remove('') 开始。

【讨论】:

当我们使用'from package import module'时,可以使用package.varname访问init文件中的代码(比如变量varname)? 否;可以使用module.varname 访问它。 但是 varname 在 pakcage 的 init 文件中。那么如何通过 modulename 访问呢?【参考方案2】:

这是当前模块系统的一个小缺陷。

当导入 module 时,你是从没有名字的当前命名空间中进行的。此命名空间内的值与 package 中的值相同,但解释器不知道。

当导入 package.module 时,您从 package 命名空间导入模块。

这就是 main.py 应该在包 forlder 之外的原因。 许多模块都有这样的组织:

package /
    main.py
    package /
        sub_package1/
        sub_package2/
        sub_package3/
        module1.py
        module2.py

仅调用 main.py 确保命名空间设置正确,即 当前命名空间是 main.py 的。它使得在 module2.py 中调用 import module1.py 变得不可能。您需要调用 import package.module1。让事情变得更简单和同质化。

是的,将当前文件夹导入为当前无名文件夹是个坏主意。 如果您超出几个脚本,它就是一个 PITA。但是当 Python 从那里开始时,它并不是完全没有意义的。

【讨论】:

以上是关于为啥“导入模块”然后“从包导入模块”再次加载模块?的主要内容,如果未能解决你的问题,请参考以下文章

python中import 和from import的区别

为啥在我导入模块时 Python 会运行我的模块,如何停止它?

python 是不是会在多次导入模块时优化模块?

在 Elixir 中,为啥在导入模块时“别名”优于“导入”?

为啥python不会在启动时自动导入每个模块?

为啥在导入模块时会显示此错误?