Python中子模块如何获取调用它的父模块?
问题描述
现有三个Python模块,期望模块能获取调用其函数的父模块名称:
- a.py
import importlib b = importlib.import_module("b") b.b()
- b.py
import importlib def b(): c = importlib.import_module("c") print(parent_module) # 期望输出 "a" c.c()
- c.py
def c(): print(parent_module) # 期望输出 "b"
尝试过以下函数,但只能获取顶层模块(两次调用均输出a):
import os from inspect import getframeinfo, stack def get_parent_name(): print('get parent module') print(os.path.splitext(os.path.basename(getframeinfo(stack()[-1][0]).filename))[0])
解决方案
问题出在stack()[-1]取的是栈底的顶层执行帧(入口模块a的帧),我们需要定位到当前函数直接调用者所在的上层帧,通过帧的全局变量获取模块名,比解析文件名更可靠。
修改后的工具函数:
import inspect def get_parent_module_name(): # 调用栈结构:stack()[0]是当前函数帧,stack()[1]是调用当前函数的帧,stack()[2]是调用者的上层帧 caller_frame = inspect.stack()[2] # 从帧的全局变量中提取模块名 module_name = caller_frame.frame.f_globals['__name__'] # 处理主模块(直接运行时__name__为__main__)的情况 if module_name == '__main__': module_name = inspect.getmodulename(caller_frame.filename) return module_name
将函数分别加入对应模块:
- b.py
import importlib import inspect def get_parent_module_name(): caller_frame = inspect.stack()[2] module_name = caller_frame.frame.f_globals['__name__'] if module_name == '__main__': module_name = inspect.getmodulename(caller_frame.filename) return module_name def b(): c = importlib.import_module("c") print(get_parent_module_name()) # 输出 "a" c.c()
- c.py
import inspect def get_parent_module_name(): caller_frame = inspect.stack()[2] module_name = caller_frame.frame.f_globals['__name__'] if module_name == '__main__': module_name = inspect.getmodulename(caller_frame.filename) return module_name def c(): print(get_parent_module_name()) # 输出 "b"
原理说明
inspect.stack()返回调用栈的FrameInfo对象列表,顺序为从当前函数到顶层入口;- 取
stack()[2]可定位到目标函数(如b())的调用者所在帧,从帧的f_globals中获取模块的__name__; - 若模块是直接运行的主程序,
__name__会是__main__,此时通过inspect.getmodulename()从文件名解析实际模块名。
内容的提问来源于stack exchange,提问作者Tnxts
相关产品推荐
相关产品推荐

