使另一个模块可从我的Python模块导入

使另一个模块可从我的Python模块导入,python,python-import,python-module,python-packaging,Python,Python Import,Python Module,Python Packaging,我有一个Python模块目录结构,如下所示: my_module |--__init__.py |--public_interface | |--__init__.py | |--my_sub_module | | |--__init__.py | | |--code.py | |--some_more_code.py |--other directories omitted 现在,public\u接口目录(以及其他几个目录)仅用于将代码组织到逻辑子单元中,作为我和其他开发人员的

我有一个Python模块目录结构,如下所示:

my_module
|--__init__.py
|--public_interface
|  |--__init__.py
|  |--my_sub_module
|  |  |--__init__.py
|  |  |--code.py
|  |--some_more_code.py
|--other directories omitted
现在,
public\u接口
目录(以及其他几个目录)仅用于将代码组织到逻辑子单元中,作为我和其他开发人员的指南。
my\u模块
的最终用户只能将其视为
my\u模块。my\u子模块
之间没有
公共接口

我编写了这些
\uuuuu init\uuuuuuuuuy.py
文件:

my\u模块.\uuuu init\uuuu.py

from.public\u接口导入*

my_模块.public_接口.\uuuu init\uuuuu.py

来自。导入我的子模块
从.some\u more\u代码导入*

我的模块.公共接口.我的子模块.\uuuuu初始化\uuuuuuuuuuuuuuy

from.code导入*
只要用户只导入顶级模块,这就可以正常工作:

导入我的\u模块
my_module.my_sub_module.whatever按预期工作
但是,这不起作用:

从我的_模块导入我的_子模块
也不是:

导入我的_模块。我的_子模块

要使最后两个导入生效,我需要做哪些更改?

导入系统只允许将实际的包和模块作为虚线模块名称的一部分直接导入,但您的:

from .public_interface import *
hack只是将
my_sub_module
作为
my_module
包的属性,而不是用于导入系统的实际子模块。它因相同的原因断开,原因如下:

from collections._sys import *
休息;是的,作为一个实现细节,
collections
包碰巧导入了别名为
\u sys
sys
,但这实际上并没有使
\u sys
成为
collections
包的子包,它只是
collections
包上的许多属性之一。从进口机械的角度来看,
my_sub_module
不再是
my_module
的子模块,正如
\u sys
集合的子模块一样;嵌套在
my_module
下的子目录中的事实与此无关

这就是说,导入系统提供了一个钩子,允许您将其他任意目录视为包的一部分。默认情况下,
\uuuuuu path\uuuuuuu
只包含到包本身的路径(因此
myu模块的
\uuuu path\uuuuuu
默认为
['/absolute/path/to/myu模块']
),但您可以根据需要通过编程操作它;解析子模块时,它将只搜索
\uuuu path\uuuu
的最终内容,就像导入顶级模块搜索
sys.path
。因此,为了解决您的特殊情况(希望导入
public\u interface
中的所有包/模块,而无需在导入行中指定
public\u interface
),只需将您的
my\u module/\uu init\uuuuuuuuuuu.py
文件更改为具有以下内容:

import os.path
__path__.append(os.path.join(os.path.dirname(__file__), 'public_interface'))
只需告诉导入系统,当发生
import mymodule.XXXX
时(
XXXX
是实名的占位符),如果找不到
my\u module/XXXX
my\u module/XXXX.py
,它应该查找
my\u module/public\u interface/XXXX
my\u module/public\u interface/XXXX.py
。如果要先搜索
public\u界面
,请将其更改为:

__path__.insert(0, os.path.join(os.path.dirname(__file__), 'public_interface'))
或者让它只检查
public\u interface
(因此
my\u module
下的任何内容都不可导入),请使用:

完全替换
\uuuu路径
的内容


旁注:您可能想知道为什么
os.path
是这个规则的一个例外;在CPython上,
os
是一个带有属性
path
的普通模块(根据平台的不同,它恰好是模块
posixpath
ntpath
),但是您可以执行
import os.path
。这是因为导入时,
os
模块会显式地(并且很有技巧地)填充
sys.modules
缓存中的
os.path
。这是不正常的,而且会带来性能成本
import os
必须始终隐式导入
os.path
,即使从未使用过
os.path
中的任何内容<代码>\uuuu路径\uuuu
避免了这个问题;除非有要求,否则不导入任何内容

通过使
my\u module/\uuu init\uuuu.py
包含以下内容,可以获得相同的结果:

import sys
from .public_interface import my_sub_module

sys.modules['my_module.my_sub_module'] = my_sub_module

这将允许人们使用
myu模块。myu子模块
只做了
导入myu模块
,但这将迫使任何
导入
myu模块
导入
公共接口
myu子模块
,即使从未使用过
myu子模块
中的任何内容<代码>操作系统路径
出于历史原因继续这样做(很久以前只使用导入操作系统的
操作系统路径
API,而且很多代码都依赖于这种错误行为,因为程序员很懒,而且可以正常工作),但是新代码不应该使用这种黑客行为。

只是OOC,为什么公共接口是隐藏的,而不是私有接口?这更像是一个例子,来说明我想要实现什么以及为什么。实际的目录名是不同的,但对于我和其他开发人员来说,公共接口和业务逻辑都是有意义的。为了实现我的目标,我只有在绝对必要的情况下才会改变它。
import sys
from .public_interface import my_sub_module

sys.modules['my_module.my_sub_module'] = my_sub_module