当前位置: 首页 > news >正文

2025-简单点-python的元类编程

类的类

自定义元类基础

创建一个自定义元类,通常需要继承 type并重写其 __new__或 __init__方法。

classVerboseMeta(type):"""一个在创建类时打印信息的元类示例"""def__new__(cls,name,bases,attrs):# 在类对象真正创建之前,我们可以修改属性字典 (attrs)print(f"[VerboseMeta] 正在创建类:{name}")# 例如,我们可以自动给类添加一个由元类注入的属性attrs['injected_by_meta']=f"由元类为{name}注入"# 必须调用父类的__new__方法来最终完成类的创建returnsuper().__new__(cls,name,bases,attrs)def__init__(self,name,bases,attrs):# 类对象已经创建,可以进行一些初始化后的操作print(f"[VerboseMeta] 类{name}初始化完成")super().__init__(name,bases,attrs)classMyClass(metaclass=VerboseMeta):defhello(self):return"Hello from MyClass"# 当Python解释器执行到上面的类定义时,VerboseMeta就已经开始工作了。# 输出:# [VerboseMeta] 正在创建类:MyClass# [VerboseMeta] 类 MyClass 初始化完成obj=MyClass()print(obj.hello())# 输出: Hello from MyClassprint(obj.injected_by_meta)# 输出: 由元类为MyClass注入

VerboseMeta的 __new__方法在类 MyClass被创建前被调用,
参数 name是类名(‘MyClass’),bases是基类元组(默认为空),attrs是一个包含类体内定义的所有属性(如方法、类变量)的字典
我们通过修改 attrs动态地为类添加了一个新属性 injected_by_meta

场景一:自动注册特定方法

假设我们想自

classRegisterMeta(type):def__new__(cls,name,bases,attrs):# 遍历类的属性,找出所有可调用且名字以大写字母开头的方法methods=[keyforkey,valueinattrs.items()ifcallable(value)andkey[0].isupper()]# 将这些方法名列表存入类的 'registered_methods' 属性中attrs['registered_methods']=methodsreturnsuper().__new__(cls,name,bases,attrs)classMyService(metaclass=RegisterMeta):defPublicMethod(self):# 以大写字母开头,将被注册return"This is a public method."defprivate_method(self):# 以小写字母开头,不会被注册return"This is a private method."print(MyService.registered_methods)# 输出:['PublicMethod']

元类 RegisterMeta在 MyService类创建时,扫描其属性,将符合条件的方名法记录到 registered_methods列表中,这对于构建插件系统或API框架非常有用

场景二:实现单例模式

classSingletonMeta(type):_instances={}# 用于存储每个类的唯一实例def__call__(cls,*args,**kwargs):# 当类被“调用”(实例化)时,此方法被触发ifclsnotincls._instances:# 如果该类还没有实例,则创建一个并存入字典instance=super().__call__(*args,**kwargs)cls._instances[cls]=instance# 返回字典中存储的该类的实例returncls._instances[cls]classDatabaseConnection(metaclass=SingletonMeta):def__init__(self):print("初始化数据库连接...")# 模拟耗时的连接建立# 测试db1=DatabaseConnection()# 输出:初始化数据库连接...db2=DatabaseConnection()print(db1isdb2)# 输出:True, 说明是同一个对象

关键在于元类的 __call__方法控制着类的实例化过程。通过检查实例是否已存在,我们确保了全局唯一性

进阶应用:迷你ORM框架

classField:"""描述字段的类"""def__init__(self,data_type):self.data_type=data_typeclassModelMeta(type):"""元类,用于收集Model子类的字段信息"""def__new__(cls,name,bases,attrs):# 跳过对基类Model本身的处理ifname=='Model':returnsuper().__new__(cls,name,bases,attrs)# 收集所有Field类型的属性fields={}forkey,valueinattrs.items():ifisinstance(value,Field):fields[key]=value# 将收集到的字段信息存入类的'_fields'属性中attrs['_fields']=fields# 假设表名就是类名的小写attrs['_table_name']=name.lower()returnsuper().__new__(cls,name,bases,attrs)classModel(metaclass=ModelMeta):"""所有模型类的基类"""pass# 定义具体的模型类classUser(Model):id=Field(int)name=Field(str)email=Field(str)# 使用print(User._table_name)# 输出:userprint(User._fields)# 输出:{'id': <__main__.Field object at ...>, ...}user=User()# 此时,user实例的类User已经通过ModelMeta元类,自动拥有了关于其字段和表名的元信息。

这个例子展示了元类的强大之处:它允许框架开发者(Model和ModelMeta)在后台完成繁琐的映射工作,而业务开发者(User类的定义者)只需以非常声明式的方式编写代码,就能实现复杂的功能。这正是Django ORM等框架的核心工作原理。

http://www.cnnetsun.cn/news/102635.html

相关文章:

  • JavaScript 动态网页开发核心问题及实现页面动态更新方法
  • Python中append()方法的使用、原理及效率解析
  • 评管理信息系统教材:过时问题、理论实践结合及专业适配性
  • 生产执行系统怎么选?2025年制造业高性价比MES系统推荐
  • MuJoCo逆向运动学实战:从理论到人形机器人运动重定向的完整指南
  • 降aigc提示词排名:10大工具+高效推荐
  • Obsidian Linter完整使用指南:让你的笔记格式统一专业
  • 理工科标题规范:8大平台+工具示例排名
  • 揭秘Vanna:用自然语言解锁数据库查询的AI黑科技
  • BDInfo终极指南:10分钟掌握蓝光光盘信息分析技巧
  • Tkinter Helper终极指南:5分钟学会可视化GUI界面开发
  • 基于Gradle8.0的插件开发
  • Gradle8.0中Transform的替代方案
  • 47、运维脚本与消息推送:从菜单到弹窗的全面指南
  • 50、脚本与函数的综合应用指南
  • XDM浏览器插件终极指南:5分钟快速上手高速下载神器
  • 如何配置一个!P地址和子网掩码?
  • EmotiVoice项目依赖项精简计划:降低部署复杂度
  • 魔盒项目开发纪实:移动端应用开发
  • 鸿蒙ArkTS与Vue3状态管理对比
  • EmotiVoice能否生成辩论赛语音?逻辑性强语调输出
  • 【必收藏】AI智能体(AI Agent)完全指南:从底层原理到落地实践,打造你的第一个智能体系统
  • 建议收藏:零基础也能玩转AI大模型:提示词工程+微调+RAG实战指南
  • 精度论文:【Class Attention Transfer Based Knowledge Distillation】
  • 邮件防泄露再升级!CACTER EDLP大模型破解隐秘泄露,防护更精准
  • 13、深入了解psad:端口扫描攻击检测器与可疑流量检测
  • affine+docker+postgresql+备份数据库
  • EmotiVoice语音风格迁移功能探索:跨语境情感复现
  • FDM 3D打印表面粗糙度降至2μm?这一新技术来了解一下!
  • EmotiVoice跨平台兼容性测试结果公布