news 2026/4/17 22:54:01

Python 3.12 Special Attribute - 08 - __module__

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python 3.12 Special Attribute - 08 - __module__

Python 3.12 Special Attribute -__module__


__module__是 Python 中一个重要的内置特殊属性,它存储了定义类、函数、方法的模块名称(字符串)。这个属性在序列化(如pickle)、动态导入、调试以及框架设计中扮演着关键角色。理解__module__有助于掌握 Python 对象的起源,以及在跨模块环境中正确地恢复对象。本文将详细解析__module__的定义、用途、不同对象上的表现,并通过多个示例演示其行为,最后从 CPython 底层探讨其实现机制。


1.__module__的基本概念

  • 定义__module__是一个字符串,表示定义该对象的模块的完整名称(如'os''collections.abc')。对于交互式环境中定义的对象,__module__通常为'__main__'
  • 适用对象
    • 类(class):存储类定义所在的模块名。
    • 函数(function):存储函数定义所在的模块名。
    • 方法(method):通常继承其所属类的__module__
  • 不适用对象:模块本身没有__module__属性(模块的__name__是其名称)。

示例

# module_example.pyclassMyClass:passdefmy_func():passprint(MyClass.__module__)# 输出: '__main__'print(my_func.__module__)# 输出: '__main__'print(__name__)# '__main__'

2. 不同对象上的__module__

2.1 类的__module__

importosprint(os.PathLike.__module__)# 输出: 'os'print(list.__module__)# 输出: 'builtins'

2.2 函数的__module__

deffoo():passprint(foo.__module__)# 输出: '__main__'(如果定义在交互式环境或主模块)

2.3 方法的__module__

方法通常与其所属类共享__module__

classC:defmethod(self):passprint(C.method.__module__)# 输出: '__main__'

2.4 动态创建的对象

通过type()动态创建的类,默认__module__是调用type的模块名,但可以手动设置:

DynamicClass=type('DynamicClass',(),{})print(DynamicClass.__module__)# 输出: '__main__'(如果在主模块中调用)

3. 用途与典型场景

  • 序列化与反序列化pickle模块在序列化一个类或函数时,会保存其__module____qualname__,以便在反序列化时能够正确地重新导入并恢复对象。
  • 动态导入:通过__module____name__(或__qualname__)可以动态地重新获取对象,用于插件系统或配置驱动。
  • 调试与日志:打印对象的__module__可以帮助快速定位对象来源。
  • 框架设计:ORM 框架(如 SQLAlchemy)利用__module__来映射数据库表与模型类,并支持跨模块的模型继承。
  • 自动文档生成:Sphinx 等工具使用__module__来组织文档的模块结构。

4. 示例与逐行解析

示例 1:查看内置类和函数的__module__

importbuiltinsprint(int.__module__)# 'builtins'print(str.__module__)# 'builtins'print(len.__module__)# 'builtins'

逐行解析

代码解释
1导入builtins只是为了展示,实际上int等已经内置。
3-6打印各个内置类型的__module__所有内置类型和函数都位于'builtins'模块中。

为什么这样写?

  • 展示内置对象的__module__都是'builtins',这有助于理解它们不属于任何用户模块。

示例 2:pickle__module__的依赖

importpickleclassMyClass:pass# 序列化data=pickle.dumps(MyClass)# 反序列化(需要在相同或可导入的模块中)reconstructed=pickle.loads(data)print(reconstructed.__module__)# 输出: '__main__'

逐行解析

代码解释
1导入pickle用于序列化。
3-4定义MyClass位于__main__模块。
7pickle.dumps(MyClass)将类对象序列化为字节流,其中包含__module____name__
10pickle.loads(data)反序列化时,pickle会使用__module__动态导入模块,然后获取类。
11打印__module__确认重建的类仍然来自'__main__'

为什么这样写?

  • 演示__module__在 pickle 中的核心作用:没有它,反序列化无法找到类定义。

示例 3:通过__module__动态重新导入类

importimportlibclassMyClass:passmodule_name=MyClass.__module__ class_name=MyClass.__name__# 动态导入模块并获取类module=importlib.import_module(module_name)cls=getattr(module,class_name)print(clsisMyClass)# True

逐行解析

代码解释
1导入importlib用于动态导入。
3-4定义MyClass类位于当前模块。
6-7获取__module____name__保存模块名和类名。
10importlib.import_module(module_name)根据模块名导入模块对象。
11getattr(module, class_name)从模块中获取类对象。
13比较确认动态获取的类与原类是同一个。

为什么这样写?

  • 演示如何利用__module__实现对象的“热加载”或插件化。

示例 4:修改__module__的影响(谨慎操作)

classOriginal:passOriginal.__module__='fake.module'# pickle 会使用修改后的模块名importpickle data=pickle.dumps(Original)# 反序列化时会在 'fake.module' 中查找 Original,大概率失败# _pickle.PicklingError:# Can't pickle <class 'fake.module.Original'>:# import of module 'fake.module' failed

逐行解析

代码解释
1-2定义类Original正常模块为__main__
4修改__module__'fake.module'不推荐这样做,会破坏 pickle 和其他依赖模块名的机制。
7-9尝试 pickle序列化成功,但反序列化时会去导入不存在的模块,导致错误。

为什么这样写?

  • 警示:不要随意修改__module__,除非你完全理解其后果。

5. 底层实现机制(CPython)

在 CPython 中,__module__的存储方式因对象类型而异:

  • 类对象(PyTypeObject:类的__module__属性存储在类的字典(tp_dict)中,键为'__module__'。当通过type.__new__创建类时,会根据当前编译时的模块上下文自动设置该值。具体来说,__module__是从创建类的栈帧中获取的__name__
  • 函数对象(PyFunctionObject:函数对象有一个专门的字段func_module(在 Python 3.11+ 中为func_module,之前版本也类似),用于存储定义函数的模块名称。在编译函数时,编译器会记录当前模块的名称,并将其赋值给函数的func_module
  • 方法对象:方法实际上是对函数的包装,其__module__通常直接引用函数的__module__,或者从所属类继承。

创建过程

  1. 当 Python 解析class语句时,会创建新的类对象,并设置其__module__为当前运行模块的__name__
  2. 对于函数,同样在编译时设置__module__
  3. 动态创建的对象(如通过type()FunctionType)如果没有显式提供__module__,则默认使用调用者的模块名(通常是__main__)。

只读性__module__在 Python 层面是可写的(因为它只是字典中的一个键或普通属性),但修改它可能导致 pickle 无法正确恢复对象,因此应视为只读。


6. 注意事项与陷阱

  • 不要随意修改__module__:修改后会影响 pickle、importlib等依赖模块名的功能,可能导致难以调试的错误。
  • 动态创建的类:使用type(name, bases, dict)创建类时,默认__module__是调用type的模块名。如果需要在其他模块中使用,应显式设置dict['__module__'] = 'your.module'
  • 嵌套类:嵌套类的__module__是其外部类所在的模块名,而不是外部类的限定名。
  • __qualname__的关系__module__+__qualname__可以唯一标识一个嵌套类或函数。
  • 在装饰器中:装饰器可能会包装函数,导致__module__指向装饰器定义的模块。使用functools.wraps可以复制原函数的__module__

7. 与其他特殊属性的关系

属性关系
__name__对象的直接名称,配合__module__可唯一标识顶级对象。
__qualname__对象的限定名称,与__module__组合可唯一标识嵌套对象。
__dict__类的__module__通常存储在__dict__中。
__class__实例的__class__指向类,而类的__module__指示类定义的位置。

8. 总结

特性说明
角色存储定义类、函数、方法的模块名称
类型str
适用对象类、函数、方法(模块无此属性)
访问方式obj.__module__
可写性可写(但不推荐)
底层类:tp_dict中的键;函数:func_module字段
典型用途pickle 序列化、动态导入、调试、框架注册
最佳实践视为只读;动态创建类时显式设置;不要随意修改

掌握__module__是深入理解 Python 对象来源和跨模块交互的基础。无论是编写可序列化的类,还是构建动态插件系统,__module__都是不可或缺的元数据。希望本文能帮助你全面掌握这一特殊属性。

如果在学习过程中遇到问题,欢迎在评论区留言讨论!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/11 23:44:17

Python爬虫实战:手把手教你如何打造MIME 类型助手!

㊗️本期内容已收录至专栏《Python爬虫实战》&#xff0c;持续完善知识体系与项目实战&#xff0c;建议先订阅收藏&#xff0c;后续查阅更方便&#xff5e; ㊙️本期爬虫难度指数&#xff1a;⭐ (基础入门篇) &#x1f250;福利&#xff1a; 一次订阅后&#xff0c;专栏内的所有…

作者头像 李华
网站建设 2026/4/17 22:53:18

从逐日NC数据到多维时空统计:Python实战SST的年、月、日及全局平均

1. 理解海表温度数据与NetCDF格式 海表温度&#xff08;Sea Surface Temperature, SST&#xff09;是海洋研究中最重要的基础数据之一。想象一下&#xff0c;你手里有一本厚厚的日历&#xff0c;每天记录着全球海洋各个位置的温度读数&#xff0c;连续记录了十几年甚至几十年。…

作者头像 李华
网站建设 2026/4/17 22:46:01

华为OD机试真题 新系统2026-04-01 C语言 实现【勇攀数字高峰】

目录 题目 思路 Code 题目 请你在给定的数字地形图中寻找登山路径,数字代表当前位置的海拔高度,要求从最低海拔出发,不断攀登,最终到达最高山峰。你需要寻找所有满足条件的登山路径。地图已经保证最低海拔和最高山峰都只有一个。 路径条件 登山规则:路径上的海拔必须严格…

作者头像 李华
网站建设 2026/4/11 23:35:33

XhsClient多账号管理架构深度解析:高性能爬虫系统实战指南

XhsClient多账号管理架构深度解析&#xff1a;高性能爬虫系统实战指南 【免费下载链接】xhs 基于小红书 Web 端进行的请求封装。https://reajason.github.io/xhs/ 项目地址: https://gitcode.com/gh_mirrors/xh/xhs XhsClient作为小红书数据采集的高性能Python库&#x…

作者头像 李华
网站建设 2026/4/11 23:35:32

JMS, ActiveMQ 学习一则炯

开发个什么Skill呢&#xff1f; 通过 Skill&#xff0c;我们可以将某些能力进行模块化封装&#xff0c;从而实现特定的工作流编排、专家领域知识沉淀以及各类工具的集成。 这里我打算来一次“套娃式”的实践&#xff1a;创建一个用于自动生成 Skill 的 Skill&#xff0c;一是用…

作者头像 李华