编程后端开发者

请谈谈在 Python 中导入模块时发生了什么。Python 是如何查找和加载模块的?在不正确组织导入时可能会出现哪些典型错误?

用 Hintsage AI 助手通过面试

答案。

当在 Python 中导入模块时,解释器会在 sys.path 列表中的目录中查找该模块。首先会查找标准模块,然后查找 .py.pyc 文件和包含 __init__.py 文件的目录(包)。

  1. 如果模块已经被导入,重复导入会直接从 sys.modules 中获取它。
  2. 如果在标准路径中找不到模块,则会抛出 ModuleNotFoundError 异常。
  3. 在导入时,模块会被转换为字节码 (.pyc) 并缓存(如果有写入权限)。

示例:

# mypkg/__init__.py (可以是空的) # mypkg/mod.py # main.py import mypkg.mod
  • 文件名、目录结构、__init__.py 的存在与否(对于 Python <3.3 是必需的)—— 这一切都很重要。

查找方式:

  • 首先是绝对导入。
  • 其次是在 sys.path 目录中的查找(当前脚本的目录总是优先)。
  • 在包中,上下文很重要(from . import ...,绝对/相对导入)。

具有陷阱的问题。

如果在你的脚本所在的目录中有一个名为 random.py 的文件,你尝试导入标准模块 random 会发生什么?

答案:

将导入我自己的本地文件 random.py,而不是标准库。难以发现的错误常常是由于模块名称与库冲突(遮蔽)。文件命名应谨慎。

由于对该主题细微差别缺乏了解而导致的实际错误示例。


故事

在一个大型项目中,模块 email.py 偶然遮蔽了标准库中的 email 模块,开发人员花了很长时间才理解为什么无法从第三方库解析邮件。


故事

在 ML 项目中,os.path 函数无法工作:主脚本旁边有一个文件 os.py,它拦截了所有对标准模块的调用。花了一个月的调试时间才找到名称冲突。


故事

在微服务 REST API 中,尝试在多个子包之间进行相对导入模型时出现了循环导入。只有在重构项目结构和明确加载模块的顺序后才解决了问题。