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

Python元类

1、概念

在Python中,一切皆对象。你定义的类(即使是内置类型)本身也是一种对象。既然类是对象,那么它们也必然由某个“东西”创建。这个创建类的“东西”就是元类(Metaclass)。

  • 元类是创建类的类。普通类定义了实例对象的行为,而元类定义了类的行为
  • 默认情况下,Python中所有的类都是由内置元类type创建的

class MyClass:passprint(type(MyClass))  # 输出:<class 'type'>
print(type(1))         # 输出:<class 'int'>
print(type("hello"))   # 输出:<class 'str'>

2、元类的工作原理:类创建过程

当你使用 class关键字定义一个类时,Python在幕后执行了以下几步,只要理解类本身就是元类的实例,就容易理解调用__new____init__的时机:

  1. 收集类定义内容:解析类定义体,获取类名、基类和包含属性/方法的字典。
  2. 确定元类:检查是否指定了自定义元类(通过metaclass关键字),若无则使用默认的type。
  3. 执行元类的__new__方法:元类的__new__方法负责创建并返回这个类对象。这是干预类创建、修改类属性(如方法、类变量)的关键阶段。
  4. 执行元类的__init__方法:元类的__init__方法负责对创建好的类对象进行初始化。
  5. 将类对象绑定到类名:最终,创建的类对象被赋值给类定义头中的类名。

type函数除了可以查看对象的类型,还可以动态地创建类,其语法如下:

MyClass = type('MyClass', (BaseClass,), {'attribute': value, 'method': my_method})

3、定义自定义元类

自定义元类通常通过继承type并重写其__new____init__方法来实现,元类的__new____init__方法在类定义阶段就被调用了

3.1 基本元类结构


class MyMeta(type):"""自定义元类,继承自 type"""def __new__(cls, name, bases, attrs):"""在类创建时调用- cls: 元类本身- name: 要创建的类名- bases: 父类元组- attrs: 类属性字典"""print(f"创建类: {name}")print(f"父类: {bases}")print(f"属性: {list(attrs.keys())}")# 必须调用 type.__new__ 来实际创建类return super().__new__(cls, name, bases, attrs)def __init__(self, name, bases, attrs):"""类初始化时调用"""super().__init__(name, bases, attrs)print(f"初始化类: {name}")# 使用元类
class MyClass(metaclass=MyMeta):x = 42def method(self):return "hello"# 输出:
# 创建类: MyClass
# 父类: ()
# 属性: ['__module__', '__qualname__', 'x', 'method']
# 初始化类: MyClass

3.2 修改类定义

元类可以在类创建时修改其属性:


class UpperCaseMeta(type):"""将类中所有非特殊属性名改为大写"""def __new__(cls, name, bases, attrs):# 过滤出需要修改的属性uppercase_attrs = {}for attr_name, attr_value in attrs.items():if not attr_name.startswith('__'):  # 不处理特殊方法uppercase_attrs[attr_name.upper()] = attr_valueelse:uppercase_attrs[attr_name] = attr_valuereturn super().__new__(cls, name, bases, uppercase_attrs)class MyClass(metaclass=UpperCaseMeta):my_attr = "value"another_attr = 42def my_method(self):return "original"# 测试
obj = MyClass()
print(hasattr(obj, 'my_attr'))      # False
print(hasattr(obj, 'MY_ATTR'))      # True
print(hasattr(obj, 'my_method'))    # False  
print(hasattr(obj, 'MY_METHOD'))    # True

4、使用场景

4.1 单例模式实现

由于类是元类的对象,因此实例化对象就类似于普通对象直接加(),就会调用元类的__call__方法

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 DatabaseConnection(metaclass=SingletonMeta):def __init__(self, connection_string):self.connection_string = connection_stringprint(f"连接到数据库: {connection_string}")def query(self, sql):return f"执行查询: {sql}"# 测试单例
db1 = DatabaseConnection("mysql://localhost:3306/mydb")
db2 = DatabaseConnection("mysql://localhost:3306/mydb")print(db1 is db2)  # True
print(db1.query("SELECT * FROM users"))

4.2 ORM(对象关系映射)框架

class Field:"""字段基类"""def __init__(self, field_type, required=True, default=None):self.field_type = field_typeself.required = requiredself.default = defaultclass CharField(Field):def __init__(self, max_length=255, **kwargs):super().__init__(str, **kwargs)self.max_length = max_lengthclass IntegerField(Field):def __init__(self, **kwargs):super().__init__(int, **kwargs)class ModelMeta(type):"""ORM 元类,用于收集字段信息"""def __new__(cls, name, bases, attrs):# 收集字段信息fields = {}for attr_name, attr_value in attrs.items():if isinstance(attr_value, Field):fields[attr_name] = attr_value# 从类属性中移除字段,避免干扰实例属性attrs[attr_name] = None# 添加_fields属性保存字段信息attrs['_fields'] = fieldsreturn super().__new__(cls, name, bases, attrs)class Model(metaclass=ModelMeta):"""模型基类"""def __init__(self, **kwargs):for field_name, field in self._fields.items():value = kwargs.get(field_name, field.default)setattr(self, field_name, value)def validate(self):"""验证字段值"""errors = []for field_name, field in self._fields.items():value = getattr(self, field_name)if value is None and field.required:errors.append(f"{field_name} is required")elif value is not None and not isinstance(value, field.field_type):errors.append(f"{field_name} must be {field.field_type.__name__}")return errors# 使用元类创建模型,子类的创建会继承父类的元类
class User(Model):name = CharField(max_length=100)age = IntegerField(required=False, default=0)email = CharField(max_length=255)# 测试
user = User(name="Alice", age=25, email="alice@example.com")
print(user.name)        # Alice
print(user.age)         # 25
print(user.validate())  # []user2 = User(name="Bob")
print(user2.validate())  # ['email is required']
http://www.sczhlp.com/news/52931/

相关文章:

  • asp.net网站恢复个人主页的英文
  • 网站推广公司兴田德润电话多少网站建设的ci设计指的是什么
  • 河北公司网站建设做断桥铝窗户的网站
  • linux apache发布php网站天津企业网站建站
  • 在建设主题网站时做网站用哪个编程语言
  • python搭建个人网站做网站需要的手续
  • c 做网站的六大对象网站关键词最多几个
  • 全球外贸网站制作教程网络科技公司实习周记
  • 网站设计公司费用网页的制作公司
  • docker redis主从实战
  • 基于dw的网站设计论文wamp在网站建设中的功能及协作关系
  • wordpress 关闭多站点wordpress微网站模板
  • 小说阅读网站开发视频电子商务网站的功能包括
  • 国外买东西的网站有哪些团购做的好的网站
  • 网站开发厦门凡科董事长
  • 百捷网站建设用手机建网站
  • 厂字型网页网站购物网站开发教程 视频
  • 住房城乡建设部官方网站spring可以做多大的网站
  • 织梦做的网站怎么传到网上做p2p网站多少钱
  • html做的好看的网站免费网站设计
  • 网站首页模板自定义西安志成网站建设公司
  • 罗湖区网站公司如何调用wordpress函数
  • 制作个人网站实例怎样下载优化大师
  • 网站开发能自学吗做网站枣庄
  • 制作一个介绍洛阳网站东营考试信息网官网
  • 北京专业网站制作企业网站开发技术
  • CppUnit框架:编写与执行单元测试
  • 锁和隔离级别的关系
  • hk域名网站汝州网站制作
  • 光谷软件园企业网站建设公司郑州房产网二手房