在导入分析后将vix添加到命名空间中
默认情况下,模块中不可见顶层作用域。模块中的globals
函数返回模块级别的作用域,而不是导入模块的作用域(参见docs)。因此,需要一些技巧将vix
放到外部作用域中。
第一个技巧。
Python中的import
语句实际上是一个函数调用,并且来自__init__.py
的代码在某个堆栈帧内执行。技巧是找到对应于导入模块的堆栈帧并污染其作用域。虽然这是可能的,但这是一种非常糟糕的做法。它违反了Python的范例,即简单的事情必须是简单的。如果您需要在顶层作用域中使用vix
,请使用import analyse.vix as vix
。作用域污染可能会导致名称冲突和非常微妙的错误。
第二个技巧。
__init__.py
中的代码仅在包的第一次加载时执行。在所有其他import analyse
语句中,Python解释器使用缓存在sys.modules
中的模块对象。我找到的唯一方法是拦截对__import__
内置函数的调用并添加作用域污染钩子。
我强烈建议避免使用这种“魔法”。不过,如果你想自己给自己挖坑,那就来吧。
将以下代码放入analyse/__init__.py
中:
from . import vix
import inspect as _inspect
_frame = _inspect.currentframe().f_back
while _frame is not None:
if "importlib._bootstrap" in _frame.f_code.co_filename:
_frame = _frame.f_back
continue
_frame.f_globals["vix"] = vix
print("DEBUG: injected vix to ", _frame)
break
del[_frame]
import builtins as _builtins
_builtin_import = _builtins.__import__
def _never_overload_import(name, globals=None, locals=None, fromlist=(), level=0):
"This function injects `vix` in every scope that imports `analyse` module"
global _builtin_import
global vix
result = _builtin_import(name, globals, locals, fromlist, level)
if name == "analyse" and globals is not None and not "vix" in globals:
globals["vix"] = vix
print("DEBUG: injected vix to ", _inspect.currentframe().f_back)
return result
_builtins.__import__ = _never_overload_import
这是我的测试方式:
- 文件
secondary.py
只加载目标模块。
import analyse
vix.draw_vix("called from secondary as `vix.draw_vix`")
- 文件
test.py
加载了 secondary.py
和 analyse
print("***Loading secondary***")
import secondary
print("***Secondary loaded***")
print("***Loading analyse***")
import analyse
print("***Analyse loaded***")
analyse.vix.draw_vix("called as `analyse.vix.draw_vix`")
vix.draw_vix("called as `vix.draw_vix`")
输出:
***Loading secondary***
DEBUG: injected vix to <frame at 0x00909AE8, file 'secondary.py', line 1, code <module>>
draw vix, called from secondary as `vix.draw_vix`
***Secondary loaded***
***Loading analyse***
DEBUG: injected vix to <frame at 0x00911C30, file 'test.py', line 6, code <module>>
***Analyse loaded***
draw vix, called as `analyse.vix.draw_vix`
draw vix, called as `vix.draw_vix`
更新日志
添加了重载__import__
函数的功能。原始答案只是将vix
对象插入到导入作用域的全局变量中,但这并不足够:在__init__.py
中的代码仅在第一次加载包时执行一次。当包在另一个文件中被导入时,它将看不到vix
模块,因为注入代码未被执行。
__import__
内置函数的重载以确保这个技巧始终有效。 - Pak Uulafrom analyse import vix
和import analyse
有什么问题? - leoschet