python - 使另一个模块可以从我的 Python 模块中导入

标签 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_interface目录(以及其他几个)仅用于将代码组织成逻辑子单元,作为我和其他开发人员的指南。 my_module 的最终用户只能将其视为 my_module.my_sub_module没有 public_interface之间。

我写了这些 __init__.py文件:

my_module.__init__.py:

from .public_interface import *




my_module.public_interface.__init__.py:

from . import my_sub_module
from .some_more_code import *




my_module.public_interface.my_sub_module.__init__.py:

from .code import *


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

import my_module

my_module.my_sub_module.whatever  # Works as intended

但是,这不起作用:

from my_module import my_sub_module

也不:

import my_module.my_sub_module

我需要改变什么才能使最后两个导入工作?

最佳答案

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

from .public_interface import *

hack 只是让 my_sub_module my_module 的一个属性包,而不是用于导入系统的实际子模块。出于同样的原因,它会中断:
from collections._sys import *

休息;是的,作为实现细节,collections包恰好导入sys别名为 _sys ,但这实际上并没有使 _sys collections 的子包,它只是 collections 上的众多属性之一包裹。从进口机械的角度来看,my_sub_module不再是 my_module 的子模块比 _sys属于 collections ;嵌套在 my_module 下的子目录中的事实无关紧要。

也就是说,导入系统提供了一个钩子(Hook),允许您将其他任意目录视为包的一部分,the __path__ attribute .默认情况下,__path__仅包含包本身的路径(因此 my_module__path__ 默认为 ['/absolute/path/to/my_module'] ),但您可以根据需要以编程方式对其进行操作;解析子模块时,它只会搜索 __path__ 的最终内容,就像导入顶级模块搜索 sys.path .因此,要解决您的特殊情况(希望 public_interface 中的所有包/模块都可以导入,而无需在导入行中指定 public_interface),只需更改您的 my_module/__init__.py文件具有以下内容:
import os.path
__path__.append(os.path.join(os.path.dirname(__file__), 'public_interface'))

所做的只是告诉导入系统,当 import mymodule.XXXX发生(XXXX 是真实姓名的占位符),如果找不到 my_module/XXXXmy_module/XXXX.py ,它应该寻找 my_module/public_interface/XXXXmy_module/public_interface/XXXX.py .如果要搜索public_interface首先,将其更改为:
__path__.insert(0, os.path.join(os.path.dirname(__file__), 'public_interface'))

或者让它只检查 public_interface (所以 my_module 下的任何内容都不能导入),请使用:
__path__[:] = [os.path.join(os.path.dirname(__file__), 'public_interface')]

替换__path__的内容完全。

旁注:您可能想知道为什么 os.path是该规则的一个异常(exception);在 CPython 上,os是一个具有属性 path 的普通模块(这恰好是模块 posixpathntpath 取决于平台),但您可以执行 import os.path .这是因为 os模块,在被导入时,显式地(并且巧妙地)填充 sys.modules os.path 的缓存.这是不正常的,并且有性能成本; import os必须始终导入 os.path隐含地,即使 os.path 中没有任何内容曾经使用过。 __path__避免了这个问题;除非要求,否则不会导入任何内容。

您可以通过制作 my_module/__init__.py 来获得相同的结果包含:
import sys
from .public_interface import my_sub_module

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

这将允许人们使用 my_module.my_submodule只做了import my_module , 但这会强制任何 importmy_module进口public_interfacemy_sub_module ,即使 my_sub_module 中没有任何内容曾经使用过。 os.path出于历史原因继续这样做(很久以前使用 os.path API 和仅 import os,并且很多代码依赖于这种不当行为,因为程序员很懒惰并且它有效),但是新代码不应该使用这个 hack .

关于python - 使另一个模块可以从我的 Python 模块中导入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57526479/

相关文章:

python - 如何透明地重定向 Python 导入?

python - IPython导入本地文件

python - 使用 py2exe 和 BeautifulSoup。脚本运行正常,但转换为 .exe 后,显示错误

python - 如何将单个元素和元组压缩为一个元组?

python - 检测网球场线拦截

python - 提供的解决 python 循环依赖的解决方案不起作用

Python - 导入全局/站点包模块而不是本地目录中的同名文件

python - pylab 找不到其模块的引用

python : While installing requirements dlib error showing on ubuntu 16. 04 网络服务器

python - 如何将子行添加到由特定列值找到的 QTreeView 行?