如何在mylibrary内部区分import mylibrary与from mylibrary import abc两种导入方式?
针对你的需求——区分import mylibrary(供othertool使用,需执行专属初始化)和from mylibrary import abc(常规使用,不执行初始化),这里提供几种可行的方案,按可靠性和实用性排序:
方案1:通过环境变量标记(最可靠)
如果能控制othertool的启动方式,或者可以协调othertool开发者添加环境变量,这是最稳定的方案:
在othertool启动时设置专属环境变量(比如MYLIBRARY_RUN_FOR_OTHERTOOL=1),然后在你的mylibrary/__init__.py中检查这个变量:
import os # 检查是否来自othertool的调用 if os.environ.get("MYLIBRARY_RUN_FOR_OTHERTOOL") == "1": # 执行othertool专属初始化代码 from . import main_othertool # 这里可以添加更多初始化逻辑,比如配置环境、加载资源等
优点:完全不受工具名称变化影响,逻辑简单且可靠,没有额外依赖。
缺点:需要协调othertool的运行配置或开发者支持。
方案2:通过调用栈上下文判断导入类型
如果无法修改othertool的配置,可以通过分析调用栈的源代码,判断当前是哪种导入方式:
import inspect def is_direct_import(): """判断当前是否是直接import mylibrary的场景""" try: # 获取调用当前模块的栈帧 caller_frame = inspect.currentframe().f_back if not caller_frame: return False # 获取调用者的源代码行 source_lines, start_line = inspect.getsourcelines(caller_frame.f_code) line_idx = caller_frame.f_lineno - start_line if line_idx < 0 or line_idx >= len(source_lines): return False current_line = source_lines[line_idx].strip() # 判断是否是直接import语句 return current_line.startswith("import mylibrary") except (OSError, IndexError): # 无法读取源代码时(比如pyc文件、交互式环境),默认返回False return False # 根据判断结果执行初始化 if is_direct_import(): from . import main_othertool
优点:无需修改othertool,纯Python实现。
缺点:如果调用者的代码是编译后的(如pyc)、压缩的,或者导入语句被拆分多行,可能判断失效。
方案3:通过父进程名称判断(需第三方依赖)
如果允许引入第三方库,可以用psutil检查父进程的名称,替代之前的sys.argv判断:
首先安装psutil:
pip install psutil
然后在__init__.py中:
import psutil def is_othertool_process(): """判断父进程是否是othertool""" try: parent_process = psutil.Process().parent() parent_name = parent_process.name() # 匹配可能的工具名称(可以扩展列表) return parent_name in ["othertool", "othertool.py", "othertool.exe"] except (psutil.NoSuchProcess, psutil.AccessDenied): return False if is_othertool_process(): from . import main_othertool
优点:比sys.argv更可靠,不受命令行参数中工具名称的位置影响。
缺点:需要依赖第三方库,且如果父进程名称被修改,仍需更新代码。
方案4:延迟初始化(适配工具调用逻辑)
如果othertool在import mylibrary后会调用特定的函数(比如mylibrary.main_othertool),可以将初始化逻辑延迟到该函数被调用时执行:
# mylibrary/__init__.py _initialized = False def main_othertool(): global _initialized if not _initialized: # 执行初始化代码 print("Running othertool initialization...") _initialized = True # 原有main_othertool的逻辑 ...
优点:无需区分导入方式,只有当工具实际使用专属功能时才初始化,避免不必要的开销。
缺点:如果othertool依赖导入时就完成初始化(比如某些全局配置),这个方案不适用。
内容的提问来源于stack exchange,提问作者geekscrap

