HoRain云--Python元类编程与描述符实战
元类和描述符是Python最魔法的特性也是框架的底层基石。ORM的字段、属性的getter/setter、单例模式都依赖它们。本文从描述符讲起深入元类并实战一个迷你ORM。一、属性访问的本质访问obj.attr时Python调用type(obj).__getattribute__。若找到数据描述符优先使用。python复制下载class User: def __init__(self): self.name Tom u User() print(u.__dict__) # {name: Tom} print(User.__dict__.keys()) # 类属性二、描述符协议实现以下任一方法即为描述符__get__(self, obj, objtype)__set__(self, obj, value)__delete__(self, obj)数据描述符实现__get__和__set__非数据描述符只实现__get__python复制下载class Descriptor: def __get__(self, obj, objtypeNone): print(get) return 42 class Foo: x Descriptor() f Foo() print(f.x) # get \n 42三、实战类型校验描述符python复制下载class Typed: def __init__(self, name, expected_type): self.name name self.expected_type expected_type def __set_name__(self, owner, name): self.name name def __get__(self, obj, objtypeNone): if obj is None: return self return obj.__dict__.get(self.name) def __set__(self, obj, value): if not isinstance(value, self.expected_type): raise TypeError(f{self.name} 必须是 {self.expected_type.__name__}) obj.__dict__[self.name] value class User: name Typed(name, str) age Typed(age, int) def __init__(self, name, age): self.name name self.age age u User(Tom, 20) # u.age abc # TypeError四、property内置描述符python复制下载class Temperature: def __init__(self, celsius): self._celsius celsius property def celsius(self): return self._celsius celsius.setter def celsius(self, value): if value -273.15: raise ValueError(低于绝对零度) self._celsius value property def fahrenheit(self): return self._celsius * 9 / 5 32 t Temperature(25) print(t.fahrenheit) # 77.0五、getattrvsgetattributepython复制下载class Foo: def __getattr__(self, name): # 只在属性找不到时调用 return f默认值: {name} def __getattribute__(self, name): # 所有属性访问都调用慎用 print(f访问 {name}) return super().__getattribute__(name)六、元类基础元类是类的类。type是所有类的元类。python复制下载# 动态创建类 User type(User, (object,), {name: Tom}) u User() print(u.name) # Tom # 自定义元类 class Meta(type): def __new__(mcs, name, bases, namespace): print(f创建类 {name}) namespace[created] True return super().__new__(mcs, name, bases, namespace) class User(metaclassMeta): pass print(User.created) # True七、元类实战单例python复制下载class SingletonMeta(type): _instances {} def __call__(cls, *args, **kwargs): if cls not in cls._instances: cls._instances[cls] super().__call__(*args, **kwargs) return cls._instances[cls] class Config(metaclassSingletonMeta): def __init__(self): self.debug False c1 Config() c2 Config() print(c1 is c2) # True八、元类实战注册表python复制下载class PluginMeta(type): registry {} def __new__(mcs, name, bases, namespace): cls super().__new__(mcs, name, bases, namespace) if name ! Plugin: mcs.registry[namespace.get(name, name)] cls return cls class Plugin(metaclassPluginMeta): name def run(self): raise NotImplementedError class EmailPlugin(Plugin): name email def run(self): print(发送邮件) class SMSPlugin(Plugin): name sms def run(self): print(发送短信) print(PluginMeta.registry) # {email: EmailPlugin, sms: SMSPlugin} plugin PluginMeta.registry[email]() plugin.run()九、实战迷你ORMpython复制下载class Field: def __init__(self, column_type): self.column_type column_type def __set_name__(self, owner, name): self.name name def __get__(self, obj, objtypeNone): if obj is None: return self return obj.__dict__.get(self.name) def __set__(self, obj, value): obj.__dict__[self.name] value class IntegerField(Field): def __init__(self): super().__init__(INTEGER) class StringField(Field): def __init__(self, max_length255): super().__init__(fVARCHAR({max_length})) class ModelMeta(type): def __new__(mcs, name, bases, namespace): if name Model: return super().__new__(mcs, name, bases, namespace) fields {} for k, v in namespace.items(): if isinstance(v, Field): fields[k] v cls super().__new__(mcs, name, bases, namespace) cls._table name.lower() cls._fields fields return cls def __init__(cls, name, bases, namespace): super().__init__(name, bases, namespace) if name ! Model: print(f表 {cls._table} 创建完成) class Model(metaclassModelMeta): def save(self): cols , .join(self._fields.keys()) placeholders , .join([%s] * len(self._fields)) sql fINSERT INTO {self._table} ({cols}) VALUES ({placeholders}) values [getattr(self, k) for k in self._fields] print(sql, values) class User(Model): name StringField(50) age IntegerField() u User() u.name Tom u.age 20 u.save() # INSERT INTO user (name, age) VALUES (%s, %s) [Tom, 20]十、总结描述符控制属性访问元类控制类创建。它们是ORM、框架、DSL的底层。日常开发不建议滥用元类但理解它们能让你读懂框架源码也能在合适场景写出优雅的代码。

相关新闻

Python打包工具深度指南:PyInstaller、cx_Freeze与Nuitka实战避坑

Python打包工具深度指南:PyInstaller、cx_Freeze与Nuitka实战避坑

简介:这是一套面向Python初学者与中小型项目开发者的图形化打包工具,解决Python程序因依赖Python环境而难以跨平台分发的核心痛点。工具基于PyInstaller深度封装,提供简洁GUI界面,用户无需记忆命令行参数,即可完成脚本…

2026/10/15 21:32:49 阅读更多 →
Delphi 12必备:Indy 10.6.3.3安装避坑与网络编程实战

Delphi 12必备:Indy 10.6.3.3安装避坑与网络编程实战

简介:Delphi 12 配套的 Indy 10.6.3.3 网络组件库源码包,为 Delphi 及 RAD Studio 开发者提供了一套跨协议的互联网通信方案,直接回应 Delphi 环境下网络组件缺失的痛点。它覆盖 TCP/IP、UDP、HTTP、SMTP、POP3、FTP 等常见协议,通…

2026/10/15 21:32:49 阅读更多 →
Agent Skills 实战:用 TaoToken 统一 Key 搭建 AI 智能体基础设施

Agent Skills 实战:用 TaoToken 统一 Key 搭建 AI 智能体基础设施

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 21:32:49 阅读更多 →

最新新闻

SpringBoot+Vue党员教育管理系统设计与实现:从需求分析到部署排坑

SpringBoot+Vue党员教育管理系统设计与实现:从需求分析到部署排坑

最近刚把一个计算机毕业设计项目完整跑通,用的是 SpringBoot Vue 的组合,题目是“党员教育和管理系统”,也可以理解成一套党校线上指导平台。如果你正好在选毕业设计题目,或者公司内部需要做一套线上学习培训系统,这个…

2026/10/15 22:27:31 阅读更多 →
CC Switch 多环境切换实战:把 Claude Code 的 endpoint 改到 TaoToken

CC Switch 多环境切换实战:把 Claude Code 的 endpoint 改到 TaoToken

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 22:27:31 阅读更多 →
基于SSM+Vue的景区容灾管理系统设计与实现

基于SSM+Vue的景区容灾管理系统设计与实现

又到一年毕业设计的季节,后台私信里很多同学都在问差不多的一个问题:SSM Vue 到底做什么题目比较稳?既要工作量够,又要技术栈主流,还得好写论文、好答辩。今天想拆解的,正是这类题目里很有代表性的一类——…

2026/10/15 22:27:31 阅读更多 →
Vue看板娘教程详细版:用TaoToken统一Key接入Live2D交互组件

Vue看板娘教程详细版:用TaoToken统一Key接入Live2D交互组件

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 22:27:31 阅读更多 →
中文短文本场景下可调试的Transformer Encoder实战

中文短文本场景下可调试的Transformer Encoder实战

1. 这不是又一篇“Transformer原理科普”,而是一份NLP工程师的实战手记你点开这个标题,大概率是刚学完《Attention Is All You Need》那篇论文,或者被BERT、GPT这些词轰炸得有点晕,想找个能真正上手、能调参、能看懂模型内部在“想…

2026/10/15 22:27:31 阅读更多 →
wow.js滚动触发动画原理与实战:IntersectionObserver轻量封装

wow.js滚动触发动画原理与实战:IntersectionObserver轻量封装

简介:这是一份轻量级网页滚动动画实现方案,面向前端初学者与网页设计师,解决网站静态内容缺乏视觉动效、用户交互体验平淡的问题。资源基于流行的wow.js库封装,通过CSS类绑定实现元素进入视口时的自动动画触发,支持淡入…

2026/10/15 22:26:22 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/15 16:18:54 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/15 19:41:51 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/15 13:48:15 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 9:49:14 阅读更多 →