news 2026/10/15 21:32:40

HoRain云--Python元类编程与描述符实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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, objtype=None): 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, objtype=None): 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

五、getattrvsgetattribute

python

复制

下载

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(metaclass=Meta): 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(metaclass=SingletonMeta): 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(metaclass=PluginMeta): 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()

九、实战:迷你ORM

python

复制

下载

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, objtype=None): 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_length=255): super().__init__(f'VARCHAR({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(metaclass=ModelMeta): def save(self): cols = ', '.join(self._fields.keys()) placeholders = ', '.join(['%s'] * len(self._fields)) sql = f"INSERT 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的底层。日常开发不建议滥用元类,但理解它们能让你读懂框架源码,也能在合适场景写出优雅的代码。

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

【Vulnhub系列】Red靶场渗透测试过程,在崩溃中崩溃

环境说明 虚拟机软件&#xff1a;VirtualBox 靶场&#xff1a;Vulnhub Red: 1 攻击机Kali&#xff1a;192.168.56.3 靶机&#xff1a;192.168.56.8 虚拟机模式&#xff1a;仅主机&#xff0c;攻击机靶机同一网段 下载链接&#xff1a;https://download.vulnhub.com/red/Red.ova…

作者头像 李华
网站建设 2026/10/15 21:31:41

32位程序突破2GB内存限制的原理与实践

简介&#xff1a;本资源聚焦32位Windows程序突破默认2GB内存限制的核心技术——Large Address Awareness&#xff08;LAA&#xff09;&#xff0c;面向C与C#中高级开发者&#xff0c;尤其适用于大数据处理、图像分析、工业软件等需在32位系统下高效利用内存的实战场景。压缩包含…

作者头像 李华
网站建设 2026/10/15 21:31:18

数字图像处理系统架构与四大应用实例:从采集到输出的完整拆解

简介&#xff1a;这份数字图像处理PPT课件面向高校学生、信息技术从业者及图像处理入门学习者&#xff0c;系统讲解数字图像处理系统的组成、分类与典型应用&#xff0c;帮助读者建立从图像采集、处理到结果输出的完整知识框架。压缩包内共1个PPT文件&#xff0c;约10.87MB&…

作者头像 李华
网站建设 2026/10/15 21:28:15

LabWindows/CVI入门实战:按钮控制LED亮灭与回调机制详解

简介&#xff1a;这份资源是一个面向LabWindows/CVI初学者与上位机开发入门者的简易工程&#xff0c;围绕按钮控件与LED控件的联动展开&#xff0c;帮助读者理解虚拟仪器界面中事件响应与状态显示的基本逻辑。工程共包含25个文件&#xff0c;压缩包约133KB&#xff0c;以C源码、…

作者头像 李华
网站建设 2026/10/15 21:28:08

人形机器人训练为何离不开真人动捕数据

1. 一场被低估的“数据劳工”觉醒&#xff1a;特斯拉工厂里悄然发生的训练数据抵制最近在几个制造业一线社群里&#xff0c;我看到一条消息反复刷屏&#xff1a;“特斯拉弗里蒙特工厂的装配线工人&#xff0c;集体拒绝为Optimus人形机器人录制动作捕捉数据。”没有通稿、没有声…

作者头像 李华