在 Python 中,是不是可以在包级别从子包中公开模块?

Posted

技术标签:

【中文标题】在 Python 中,是不是可以在包级别从子包中公开模块?【英文标题】:In Python, is it possible to expose modules from subpackages at package level?在 Python 中,是否可以在包级别从子包中公开模块? 【发布时间】:2016-11-03 00:11:36 【问题描述】:

我有以下难题。我正在尝试从父包级别的包的子包中公开一些模块。

文件夹结构基本上是这样的:

script.py
package/
    __init__.py
    module1.py
    subpackage/
        __init__.py
        submodule1.py
        submodule2.py

在我目前必须写的script.py文件中

from package.subpackage.submodule1 import foo

如果我想从 submodule1.py 文件中导入某些内容,但我希望能够在包级别公开文件 submodule1.pysubmodule2.py,以便我的所有导入看起来像

from package.module1 import bar
from package.submodule1 import foo
from package.submodule2 import goo

请注意,我不想在package 级别公开barfoogoo,即

from package import bar
from package import foo

因为在我的情况下,模块之间的分离仍然很重要。

这甚至可能吗? __init__.py 文件中是否有这样做的技巧?

谢谢!

【问题讨论】:

【参考方案1】:

出于您的目的,python 模块只是名称空间。也就是说,模块全局变量中的所有内容都可以作为module.thingy 导入和使用。您可能已经注意到,在许多模块中,您还可以找到一些内置函数。例如,logging.os 就是普通的 os 模块。

因此,在您的包 (package/__init__.py) 中导入您想要的任何内容,并将其绑定到您想要公开的名称。

# package/__init__.py
# import package.module1 as module1  # one *can* do this, but its at best without benefit (see comments)
import package.subpackage.submodule1 as submodule1
import package.subpackage.submodule2 as submodule2

这允许import package.submodule1import package.submodule1 as foo

请注意,这种简单的方法不会允许您执行from package.submodule1 import bar。为此,您需要一个实际的虚拟模块。

# package/submodule1/__init__.py
from package.subpackage.submodule1 import *

【讨论】:

只要确保永远不要隐藏子包或子模块名称。像from .foo import foo 这样的东西会破坏foo 子模块的导入。 @user2357112 你测试过这个吗?我只试过os.path = None; from os.path import dirname,它工作正常。我提到的虚拟模块正是需要的,因为导入机制似乎更喜欢实际模块(具有__init__.py)而不是父命名空间。 恐怕我尝试了你的建议,但是在运行script.py 时,如果我按照你的建议写import .subpackage.submodule1 as submodule1,我会得到SyntaxError,如果我写@987654338,我会得到ImportError: No module named subpackage.submodule1 @(即不加. @MarcoSelvi '.'标记相对导入。它只能在包内使用,不能在交互式会话中使用。您可以将其替换为package.subpackage.submodule2 @MisterMiyagi:但是如果你尝试from os import path,你会得到None。进入你阴影的实际模块变得非常尴尬。【参考方案2】:

是的,这是可能的。 让我们一步一步来看看会发生什么;

    当您执行from package.submodule1 import foo 时,检查sys.modules 是否有package。 如果没有找到package/__init__.py,则运行并加载 再次检查sys.modules 是否为package.submodule1 如果未找到,则检查 package/submodule1.py 是否存在。

我们可以通过在sys.modules 中为第2 步中的package.submodule1 输入一个条目来通过第3 步。

package/__init__.py

import sys
from .subpackage import submodule1
from .subpackage import submodule2

for module in (submodule1, submodule2):
    full_name = '.'.format(__package__, module.__name__.rsplit('.')[-1])
    sys.modules[full_name] = sys.modules[module.__name__]

【讨论】:

以上是关于在 Python 中,是不是可以在包级别从子包中公开模块?的主要内容,如果未能解决你的问题,请参考以下文章

具有相同名称的 Python 模块(即,在包中重用标准模块名称)

在包中定义类

在包中运行模块没有模块错误[重复]

R:我如何在包中添加额外的功能?

在包中覆盖“defun”

我如何在包中读取函数和过程 body/ddl?