在 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.py
和 submodule2.py
,以便我的所有导入看起来像
from package.module1 import bar
from package.submodule1 import foo
from package.submodule2 import goo
请注意,我不想在package
级别公开bar
、foo
和goo
,即不
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.submodule1
和import 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 中,是不是可以在包级别从子包中公开模块?的主要内容,如果未能解决你的问题,请参考以下文章