gpt4 book ai didi

python - 从包的 __init__.py 中屏蔽 python 子模块

转载 作者:太空狗 更新时间:2023-10-30 01:06:56 29 4
gpt4 key购买 nike

精简版

特定设置要求我在 __init__.py 中创建局部变量应该屏蔽来自同一个包的模块。

例如变量 y (在 __init__.py 的本地上下文中)应隐藏模块 y.py .声明import x.y应产生局部变量而不是加载模块。

如果您不想阅读具体设置,请向下滚动到问题;不说细节也能理解。

详细说明

我已经实现了一组 Python 2.7 包,每个包都可能需要单独的配置设置。为方便起见,我计划为每个包 提供配置默认值,任何使用这些包的人都可以在本地覆盖这些默认值。

(这样做的基本原理是在将应用程序部署到运行特定环境(服务器、工作站、笔记本电脑等)的机器时分发默认设置,但同时允许覆盖配置而不会弄乱更新本地存储库或重置代码更新的本地适配。)

目录结构示例为:

~/pkg/
|
+- package_a/
| |
| +- __init__.py
| +- mod_x.py
| +- mod_y.py
|
+- package_b/
| |
| +- __init__.py
| +- mod_z.py
|
+- config/
| |
| +- __init__.py
| +- package_a.py # Should locally override <pkg>_sample.py
| +- package_a_sample.py
| +- package_b_sample.py
|
+- test_this.py

我想访问存储在 config/ 下的设置像常规模块导入,例如:

# ~/pkg/test_this.py
import config.package_a as cfg_a

...但是让它隐式切换到覆盖文件(如果存在)。

我的解决方法

为了以某种方式使该过程自动化,我动态创建了指向正确配置文件导入的局部变量。使用 imp包,我可以导入一个模块并同时专门命名它。 (即在运行时,您无法区分加载了 <pkg>_sample.py 还是 <pkg>.py 来提供配置。)

我最终得到了这个:

# ~/pkg/config/__init__.py
import os
import imp

__all__ = ['datastore']
_cfgbase = os.path.dirname(os.path.realpath(__file__))

for cfgmodule in __all__:
if os.path.isfile(os.path.join(_cfgbase, cfgmodule + '.py')):
locals()[cfgmodule] = imp.load_source(
cfgmodule, os.path.join(_cfgbase, cfgmodule + '.py'))
else:
locals()[cfgmodule] = imp.load_source(
cfgmodule, os.path.join(_cfgbase, cfgmodule + '_sample.py'))

这实际上创建了对所需源文件的本地引用(当 <pkg>_sample.py 存在于 <pkg>.py 中时省略 config/

如果使用 from config import package_a as cfg_a,我可以从其他模块/脚本使用它.

问题

本质上,这个问题可能会回到众所周知的import x.y vs from x import y。 -事物。

但是这里有区别。

我知道import x.y需要 y成为一个模块。是否有任何可能将模块隐藏在其包的 __init__.py 中?并提供局部变量 instad 导入

  • from x import y产生局部变量 y来自 x__init__.py
  • import x.y 总是 导入模块,即使是局部变量 y存在于 __init__.py .

我不能强制每个人总是使用前一个 import 语句,人们喜欢在他们的代码中使用后一个。

这里有什么建议吗?

已编辑:固定标题。抱歉。

解决方案

感谢@martijn-pieters 指出 sys.modules .

实际上,如果不显式地将新导入添加到 sys.modules,我的方法会非常有效,因为我刚刚未能正确命名新导入:

locals()[cfgmodule] j= imp.load_source(
'config.' + cfgmodule, os.path.join(_cfgbase, cfgmodule + '.py'))

这解决了问题,因为它没有使用其规范 名称(此处:package_a)注册新的子模块,而是将其注册为我的 config 的子模块。包。

非常感谢!

最佳答案

import x.y 并不真正要求 y 成为一个模块。 import x.ysys.modules 结构中查找 'x''x.y' 键。如果两者都找到,则 x 绑定(bind)到 sys.modules['x']。只有当 'x.y' 不存在时,Python 才会寻找要加载的模块。

那么技巧就是将你的 y 填充到 sys.modules 中:

sys.modules['x.y'] = y

关于python - 从包的 __init__.py 中屏蔽 python 子模块,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34266878/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com