使另一个模块可从我的Python模块导入
我有一个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接口目录(以及其他几个目录)仅用于将代码组织到逻辑子单元中,作为我和其他开发人员的
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