导入与模块同名的 classes/functions

Importing classes/functions with same name as module

假设我使用具有以下结构的 python 包:

package/
   bar.py
   foo.py
   __init__.py

bar.py 包含 class bar 并且 foo.py 包含函数 foo。 当我想导入 function/class 时,我必须写

from package.bar import bar
from package.foo import foo

或者我可以写

from package import bar
from package import foo

更普遍的问题: 当我导入与 class/function 同名的模块时,是否可以始终省略 class/function 名称?

不,您不能省略模块或对象名称。没有任何机制可以隐式执行此类导入。

来自Zen of Python:

Explicit is better than implicit.

请注意,导入 模块本身 也应该始终是一个有效的选项。如果 from package import bar 导入了 package.bar.bar 对象,那么您将不得不费尽心思才能访问 package.bar 模块本身。

此外,这种隐式行为(自动导入模块中包含的对象而不是模块本身)会导致令人困惑的不一致。

  • import package.bar 为您的命名空间添加了什么?引用 package.bar 是模块还是包含的对象?
  • 当您重命名所包含的对象时,导入此类名称的代码会发生什么情况? from package import bar 然后给你模块吗?一些操作仍然会成功,导致奇怪的、难以调试的错误,而不是明确的 ImportError 异常。

一般来说,Python 模块很少只包含 一个 东西。 Python 不是 Java,模块由密切相关的对象组组成,而不仅仅是一个 class 或函数。

现在,包中存在固有的名称空间冲突; from package import foo 可以引用在 package 模块上设置的名称, 可以引用嵌套的模块名称。在这种情况下,Python 将首先查看 package 命名空间。

这意味着您可以明确决定在包级别提供foobar对象,在package/__init__.py中:

# in package/__init__.py
from .foo import foo
from .bar import bar

现在 from package import foofrom package import bar 将为您提供那些对象,屏蔽嵌套模块。

将对象从子模块导入包命名空间的一般机制是编写 public API 同时仍使用内部模块对代码进行逻辑分组的常用方法。例如Python标准库中的json.JSONDecodeError exception是在json.exceptions模块中定义的,然后导入到json/__init__.py中。但是,我通常不鼓励屏蔽子模块;但是 foobar 进入了具有不同名称的模块。