Python元类与描述符的魔法世界

部署运行你感兴趣的模型镜像

目录

元类的工作原理

类也是类

元类的创建过程

实用元类

描述符协议深度应用

实战

ORM

简化版ORM

元类的最佳实践

描述符设计模式


元类的工作原理

元类是用来创建类的“类”,它控制类的创建过程。默认情况下,Python中所有类的元类是type。
通过自定义元类,可以在类创建时动态修改类的属性、方法,甚至控制类的继承行为。

类也是对象,在python里一切皆是对象,包括类本身

类也是类

def explore_class_as_object():
    """探索类作为对象的特性"""
    
    class MyClass:
        def __init__(self, value):
            self.value = value
        
        def method(self):
            return f"Value is {self.value}"
    
    print("=== 类也是对象 ===")
    print(f"MyClass的类型: {type(MyClass)}")   #<class 'type'>
    print(f"MyClass是否是对象: {isinstance(MyClass, object)}") #True
    print(f"MyClass的ID: {id(MyClass)}")
    print(f"MyClass的属性: {dir(MyClass)}")
    
    # 类可以像对象一样被操作
    print(f"类的名称: {MyClass.__name__}")    #类的名称: MyClass
    print(f"类的模块: {MyClass.__module__}")  #类的模块: __main__
    print(f"类的基类: {MyClass.__bases__}")   #类的基类: (<class 'object'>,)
    
    # 甚至可以给类动态添加属性
    MyClass.class_variable = "I'm a class variable"
    print(f"动态添加的属性: {MyClass.class_variable}") #动态添加的属性: I'm a class variable
    return MyClass

explore_class_as_object()

元类的创建过程

import time
class MetaclassDemo:
    """演示元类的创建过程""" 
    @staticmethod
    def manual_class_creation():
        """手动创建类的过程"""
        print("=== 手动类创建过程 ===")
        
        # 步骤1: 准备类的命名空间
        def init_method(self, value):
            self.value = value
        
        def str_method(self):
            return f"ManualClass(value={self.value})"
        
        # 步骤2: 创建类的字典
        class_dict = {
            '__init__': init_method,
            '__str__': str_method,
            'class_var': 'I am manually created'
        }
        
        # 步骤3: 使用type()创建类
        ManualClass = type('ManualClass', (object,), class_dict)
        print(f"手动创建的类: {ManualClass}")
        print(f"类的名称: {ManualClass.__name__}")
        print(f"类的基类: {ManualClass.__bases__}")
        
        # 测试创建的类
        instance = ManualClass("test_value")
        print(f"实例: {instance}")
        print(f"实例的值: {instance.value}")
        return ManualClass
    
    @staticmethod
    def demonstrate_class_creation_hooks():
        """演示类创建的钩子方法"""
        class TrackedMeta(type):
            """跟踪类创建过程的元类"""
            def __new__(mcs, name, bases, namespace, **kwargs):
                print(f"   创建类 {name}")
                print(f"   基类: {bases}")
                print(f"   命名空间键: {list(namespace.keys())}")
                print(f"   额外参数: {kwargs}")
                
                # 在类创建前修改命名空间
                namespace['_created_by'] = 'TrackedMeta'
                namespace['_creation_time'] = time.time()
                
                # 调用父类的__new__创建类
                cls = super().__new__(mcs, name, bases, namespace)
                print(f" 类 {name} 创建完成")
                return cls
            
            def __init__(cls, name, bases, namespace, **kwargs):
                print(f" 初始化类 {name}")
                super().__init__(name, bases, namespace)
                
                # 类创建后的初始化工作
                cls._instances = []
            
            def __call__(cls, *args, **kwargs):
                print(f" 创建 {cls.__name__} 的实例")
                instance = super().__call__(*args, **kwargs)
                cls._instances.append(instance)
                return instance
        print("\n=== 类创建钩子演示 ===")
        
        class TrackedClass(metaclass=TrackedMeta, custom_param="test"):
            def __init__(self, name):
                self.name = name
            
            def __str__(self):
                return f"TrackedClass({self.name})"
        
        print(f"\n创建的类信息:")
        print(f"  创建者: {TrackedClass._created_by}")
        print(f"  创建时间: {TrackedClass._creation_time}")
        
        # 创建实例
        instance1 = TrackedClass("Alice")
        instance2 = TrackedClass("Bob")
        
        print(f"实例列表: {TrackedClass._instances}")
        return TrackedClass

# 测试元类演示
demo = MetaclassDemo()
manual_class = demo.manual_class_creation()
tracked_class = demo.demonstrate_class_creation_hooks()

手动创建类的过程:

通过内置函数type(),可以手动创建一个类:1:准备类的命名空间,定义类的方法(如__init__和__str__)。2:构造类的字典,将方法和属性放入字典中。3:调用type()函数,传入类名、基类元组和类字典,动态生成类。

元类的钩子方法详解:

自定义元类继承自type,重写以下三个关键方法,控制类的创建和实例化流程:

1、 __new__(mcs, name, bases, namespace, **kwargs):类创建的第一步,负责构造类对象。可以在这里修改类的命名空间(如添加属性_created_by、_creation_time)调用super().__new__()完成类的真正创建。适合做类属性的自动注入、注册等操作。

2、 __init__(cls, name, bases, namespace, **kwargs):类创建完成后的初始化阶段。可以初始化类级别的状态(如示例中初始化_instances列表用于跟踪实例)。这里的cls是新创建的类对象。

3、__call__(cls, *args, **kwargs):控制类的实例化过程。在调用类创建实例时触发。可以在这里添加实例创建的日志、缓存或统计功能。示例中将所有实例保存到_instances列表,方便后续管理。

实用元类

class UtilityMetaclasses:
    """实用的元类模式集合"""
    
    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 ValidatedMeta(type):
        """属性验证元类"""
        
        def __new__(mcs, name, bases, namespace):
            # 收集所有需要验证的属性
            validators = {}
            for key, value in namespace.items():
                if hasattr(value, '_validator'):
                    validators[key] = value._validator
            
            namespace['_validators'] = validators
            
            # 重写__setattr__以支持验证
            original_setattr = namespace.get('__setattr__', object.__setattr__)
            
            def validated_setattr(self, name, value):
                if name in self._validators:
                    self._validators[name](value)
                original_setattr(self, name, value)
            
            namespace['__setattr__'] = validated_setattr
            
            return super().__new__(mcs, name, bases, namespace)
    
    class AutoPropertyMeta(type):
        """自动属性元类"""
        
        def __new__(mcs, name, bases, namespace):
            # 为所有以_开头的属性创建property
            for key, value in list(namespace.items()):
                if key.startswith('_') and not key.startswith('__'):
                    prop_name = key[1:]  # 去掉下划线
                    if prop_name not in namespace:
                        namespace[prop_name] = mcs._create_property(key)
            
            return super().__new__(mcs, name, bases, namespace)
        
        @staticmethod
        def _create_property(private_name):
            def getter(self):
                return getattr(self, private_name)
            
            def setter(self, value):
                setattr(self, private_name, value)
            
            return property(getter, setter)

def test_utility_metaclasses():
    """测试实用元类"""
    
    print("=== 实用元类测试 ===")
    
    # 测试单例元类
    class DatabaseConnection(metaclass=UtilityMetaclasses.SingletonMeta):
        def __init__(self):
            self.connection_id = id(self)
            print(f"创建数据库连接: {self.connection_id}")
    
    print("\n1. 单例模式测试:")
    db1 = DatabaseConnection()
    db2 = DatabaseConnection()
    print(f"db1 is db2: {db1 is db2}")
    
    # 测试验证元类
    def positive_validator(value):
        if value <= 0:
            raise ValueError("值必须为正数")
    
    class Product(metaclass=UtilityMetaclasses.ValidatedMeta):
        def __init__(self, name, price):
            self.name = name
            self.price = price
        
        # 为price属性添加验证器
        price = property(lambda self: self._price)
        price._validator = positive_validator
    
    print("\n2. 属性验证测试:")
    try:
        product = Product("Laptop", 1000)
        print(f"产品创建成功: {product.name}, ${product.price}")
        product.price = -100  # 这会触发验证错误
    except ValueError as e:
        print(f"验证错误: {e}")
    
    # 测试自动属性元类
    class Person(metaclass=UtilityMetaclasses.AutoPropertyMeta):
        def __init__(self, name, age):
            self._name = name
            self._age = age
    
    print("\n3. 自动属性测试:")
    person = Person("Alice", 25)
    print(f"通过属性访问: {person.name}, {person.age}")
    person.name = "Bob"
    print(f"修改后: {person.name}")

test_utility_metaclasses()

单例模式元类

属性验证元类

自动属性元类

通过元类的__call__方法控制实例化过程,确保一个类只会创建一个实例。

使用类变量_instances字典缓存已创建的实例。
每次调用类创建实例时,先检查缓存,若存在则直接返回。

在类创建时收集带有验证器的属性,并重写__setattr__方法,实现属性赋值时自动验证。
实现:遍历类命名空间,寻找带有_validator属性的属性。将验证器函数存入_validators字典。重写__setattr__,在赋值前调用对应的验证器。
自动为所有以单下划线开头的私有属性生成对应的property,实现属性的封装与访问控制。
实现:在__new__方法中遍历命名空间,查找以_开头但不以__开头的属性。
为每个私有属性生成对应的getter和setter,绑定为公开属性
应用场景:需要全局唯一实例的资源管理,如数据库连接、配置管理器等。
测试结果:DatabaseConnection类通过该元类实现单例,db1 is db2返回True,证明实例唯一。
应用场景:需要对属性赋值进行严格校验的场景,如数据模型、配置参数等。
测试结果:Product类的price属性绑定了正数验证器,赋值负数时抛出ValueError,保证数据合法。
应用场景:需要简化属性封装代码,避免手动写大量property的场景。
测试结果:Person类自动生成name和age属性,支持直接访问和赋值,代码简洁优雅。

描述符协议深度应用

描述符是实现了__get____set____delete__方法的对象,用于管理另一个对象的属性访问。通过描述符,可以自定义属性的读取、赋值和删除行为。

class DescriptorProtocol:
    """完整的描述符协议演示"""
    class BasicDescriptor:
        """基础描述符实现"""
        
        def __init__(self, name=None):
            self.name = name
            self.data = {}
        
        def __set_name__(self, owner, name):
            """Python 3.6+的新特性,自动设置属性名"""
            self.name = name
            print(f" 描述符 {name} 绑定到类 {owner.__name__}")
        
        def __get__(self, instance, owner):
            """获取属性值"""
            if instance is None:
                return self
            
            value = self.data.get(id(instance), "未设置")
            print(f" 获取 {owner.__name__}.{self.name} = {value}")
            return value
        
        def __set__(self, instance, value):
            """设置属性值"""
            print(f" 设置 {instance.__class__.__name__}.{self.name} = {value}")
            self.data[id(instance)] = value
        
        def __delete__(self, instance):
            """删除属性"""
            print(f" 删除 {instance.__class__.__name__}.{self.name}")
            self.data.pop(id(instance), None)
    
    class TypedDescriptor:
        """类型检查描述符"""
        
        def __init__(self, expected_type, default=None):
            self.expected_type = expected_type
            self.default = default
            self.data = {}
        
        def __set_name__(self, owner, name):
            self.name = name
        
        def __get__(self, instance, owner):
            if instance is None:
                return self
            return self.data.get(id(instance), self.default)
        
        def __set__(self, instance, value):
            if not isinstance(value, self.expected_type):
                raise TypeError(
                    f"{self.name} 必须是 {self.expected_type.__name__} 类型,"
                    f"得到 {type(value).__name__}"
                )
            self.data[id(instance)] = value
        
        def __delete__(self, instance):
            self.data.pop(id(instance), None)
    
    class ValidatedDescriptor:
        """带验证的描述符"""
        def __init__(self, validator=None, default=None):
            self.validator = validator
            self.default = default
            self.data = {}
        
        def __set_name__(self, owner, name):
            self.name = name
        
        def __get__(self, instance, owner):
            if instance is None:
                return self
            return self.data.get(id(instance), self.default)
        
        def __set__(self, instance, value):
            if self.validator:
                self.validator(value)
            self.data[id(instance)] = value
        
        def __delete__(self, instance):
            self.data.pop(id(instance), None)

def test_descriptors():
    """测试描述符"""
    print("=== 描述符协议测试 ===")
    # 定义验证函数
    def positive_number(value):
        if value <= 0:
            raise ValueError("必须是正数")
    
    def valid_email(value):
        if '@' not in value:
            raise ValueError("无效的邮箱格式")
    
    class User:
        # 使用不同类型的描述符
        name = DescriptorProtocol.BasicDescriptor()
        age = DescriptorProtocol.TypedDescriptor(int, 0)
        salary = DescriptorProtocol.ValidatedDescriptor(positive_number, 0)
        email = DescriptorProtocol.ValidatedDescriptor(valid_email, "")
        
        def __init__(self, name, age, salary, email):
            self.name = name
            self.age = age
            self.salary = salary
            self.email = email
        
        def __str__(self):
            return f"User(name={self.name}, age={self.age}, salary={self.salary}, email={self.email})"
    
    print("\n1. 创建用户:")
    user = User("li", 25, 50000, "alice@example.com")
    print(user)
    print("\n2. 修改属性:")
    user.name = "li mrs"
    user.age = 26
    print("\n3. 类型检查测试:")
    try:
        user.age = "not a number"
    except TypeError as e:
        print(f"类型错误: {e}")
    print("\n4. 验证测试:")
    try:
        user.salary = -1000
    except ValueError as e:
        print(f"验证错误: {e}")
    try:
        user.email = "invalid-email"
    except ValueError as e:
        print(f"验证错误: {e}")
    print("\n5. 删除属性:")
    del user.name
    print(f"删除后的name: {user.name}")

test_descriptors()

高级属性描述符

import weakref

class AdvancedDescriptors:
    """高级描述符模式"""
    class CachedProperty:
        """缓存属性描述符"""
        def __init__(self, func):
            self.func = func
            self.name = func.__name__
            self.__doc__ = func.__doc__
        
        def __get__(self, instance, owner):
            if instance is None:
                return self
            # 检查是否已缓存
            cache_name = f'_cached_{self.name}'
            if hasattr(instance, cache_name):
                print(f" 使用缓存值: {self.name}")
                return getattr(instance, cache_name)
            
            # 计算并缓存值
            print(f" 计算属性: {self.name}")
            value = self.func(instance)
            setattr(instance, cache_name, value)
            return value
        
        def __set__(self, instance, value):
            # 允许手动设置缓存值
            cache_name = f'_cached_{self.name}'
            setattr(instance, cache_name, value)
        
        def __delete__(self, instance):
            # 清除缓存
            cache_name = f'_cached_{self.name}'
            if hasattr(instance, cache_name):
                delattr(instance, cache_name)
    
    class ObservableDescriptor:
        """可观察的描述符"""
        def __init__(self, default=None):
            self.default = default
            self.data = weakref.WeakKeyDictionary()
            self.observers = weakref.WeakKeyDictionary()
        
        def __set_name__(self, owner, name):
            self.name = name
        
        def __get__(self, instance, owner):
            if instance is None:
                return self
            return self.data.get(instance, self.default)
        
        def __set__(self, instance, value):
            old_value = self.data.get(instance, self.default)
            self.data[instance] = value
            
            # 通知观察者
            if instance in self.observers:
                for callback in self.observers[instance]:
                    callback(instance, self.name, old_value, value)
        
        def add_observer(self, instance, callback):
            """添加观察者"""
            if instance not in self.observers:
                self.observers[instance] = []
            self.observers[instance].append(callback)
        
        def remove_observer(self, instance, callback):
            """移除观察者"""
            if instance in self.observers:
                if callback in self.observers[instance]:
                    self.observers[instance].remove(callback)
    
    class LazyDescriptor:
        """延迟加载描述符"""
        def __init__(self, loader_func):
            self.loader_func = loader_func
            self.data = weakref.WeakKeyDictionary()
        
        def __set_name__(self, owner, name):
            self.name = name
        
        def __get__(self, instance, owner):
            if instance is None:
                return self
            # 检查是否已加载
            if instance not in self.data:
                print(f" 延迟加载: {self.name}")
                self.data[instance] = self.loader_func(instance)
            return self.data[instance]

def test_advanced_descriptors():
    """测试高级描述符"""
    print("=== 高级描述符测试 ===")
    class DataProcessor:
        # 缓存属性
        @AdvancedDescriptors.CachedProperty
        def expensive_calculation(self):
            """昂贵的计算,结果会被缓存"""
            import time
            print("执行昂贵的计算...")
            time.sleep(0.1)  # 模拟耗时操作
            return sum(range(1000000))
        
        # 可观察属性
        status = AdvancedDescriptors.ObservableDescriptor("idle")
        # 延迟加载属性
        def _load_config(self):
            print("从文件加载配置...")
            return {"setting1": "value1", "setting2": "value2"}
        
        config = AdvancedDescriptors.LazyDescriptor(_load_config)
        def __init__(self, name):
            self.name = name
            
            # 为status属性添加观察者 - 通过类访问描述符对象
            def status_changed(instance, attr_name, old_value, new_value):
                print(f" {instance.name} 的 {attr_name} 从 {old_value} 变为 {new_value}")
            # 通过类而不是实例来访问描述符对象
            descriptor = type(self).status
            descriptor.add_observer(self, status_changed)
    
    print("\n1. 缓存属性测试:")
    processor = DataProcessor("Processor1")
    # 第一次访问会计算
    result1 = processor.expensive_calculation
    print(f"第一次结果: {result1}")
    # 第二次访问使用缓存
    result2 = processor.expensive_calculation
    print(f"第二次结果: {result2}")
    print("\n2. 可观察属性测试:")
    processor.status = "running"
    processor.status = "completed"
    processor.status = "idle"
    print("\n3. 延迟加载测试:")
    # 第一次访问会加载
    config1 = processor.config
    print(f"配置: {config1}")
    # 第二次访问使用已加载的数据
    config2 = processor.config
    print(f"再次访问配置: {config2}")

if __name__ == "__main__":
    test_advanced_descriptors()

缓存属性(CachedProperty):通过描述符缓存计算结果,避免重复计算,提升性能。支持手动设置和删除缓存。

可观察属性(ObservableDescriptor):属性值变化时通知注册的观察者,适合实现事件驱动和响应式编程。

延迟加载属性(LazyDescriptor):属性首次访问时才加载数据,节省资源,适合配置加载、懒初始化等场景。

实战

ORM

ORM(Object-Relational Mapping,面向对象关系映射)

Django ORM的魔法

# Django中这样定义模型
class User(models.Model):
    name = models.CharField(max_length=100)
    email = models.EmailField()
    age = models.IntegerField()

# 但实际上发生了什么?
user = User(name="Alice", email="alice@example.com", age=25)
print(type(user.name))  # <class 'str'> 而不是 CharField
print(User.objects.all())  # 神奇的查询接口从哪来的? 这背后的魔法正是元类和描述符的杰作

现在元类和描述符知识应用到实际项目中,构建一个完整的ORM框架

简化版ORM

import sqlite3
from typing import Any, List, Optional

class SimpleORM:
    """简化版ORM框架"""
    class Field:
        """字段基类"""
        def __init__(self, sql_type: str, primary_key=False, default=None):
            self.sql_type = sql_type
            self.primary_key = primary_key
            self.default = default
            self.name = None
        
        def __set_name__(self, owner, name):
            self.name = name
        
        def to_sql(self):
            """生成SQL字段定义"""
            parts = [self.name, self.sql_type]
            if self.primary_key:
                parts.append("PRIMARY KEY")
            if self.default is not None:
                parts.append(f"DEFAULT {self.default}")
            return " ".join(parts)
    
    class IntegerField(Field):
        def __init__(self, primary_key=False, default=None):
            super().__init__("INTEGER", primary_key, default)
    
    class TextField(Field):
        def __init__(self, default=None):
            super().__init__("TEXT", False, default)
    
    class Model:
        """模型基类"""
        _table_name = None
        _fields = {}
        
        def __init__(self, **kwargs):
            for field_name in self._fields:
                value = kwargs.get(field_name, self._fields[field_name].default)
                setattr(self, field_name, value)
        
        def __init_subclass__(cls, **kwargs):
            """自动收集字段信息"""
            cls._fields = {}
            for attr_name, attr_value in cls.__dict__.items():
                if isinstance(attr_value, SimpleORM.Field):
                    cls._fields[attr_name] = attr_value
                    attr_value.__set_name__(cls, attr_name)
            
            if cls._table_name is None:
                cls._table_name = cls.__name__.lower()
        
        @classmethod
        def create_table(cls, conn):
            """创建数据表"""
            field_defs = [field.to_sql() for field in cls._fields.values()]
            sql = f"CREATE TABLE IF NOT EXISTS {cls._table_name} ({', '.join(field_defs)})"
            conn.execute(sql)
            conn.commit()
        
        def save(self, conn):
            """保存对象到数据库"""
            field_names = list(self._fields.keys())
            values = [getattr(self, name) for name in field_names]
            placeholders = ', '.join(['?' for _ in field_names])
            
            sql = f"INSERT INTO {self._table_name} ({', '.join(field_names)}) VALUES ({placeholders})"
            conn.execute(sql, values)
            conn.commit()
        
        @classmethod
        def all(cls, conn) -> List['Model']:
            """获取所有记录"""
            sql = f"SELECT * FROM {cls._table_name}"
            cursor = conn.execute(sql)
            
            results = []
            for row in cursor.fetchall():
                kwargs = {name: row[i] for i, name in enumerate(cls._fields)}
                results.append(cls(**kwargs))
            
            return results
        
        @classmethod
        def filter(cls, conn, **kwargs) -> List['Model']:
            """条件查询"""
            conditions = [f"{key} = ?" for key in kwargs]
            values = list(kwargs.values())
            
            sql = f"SELECT * FROM {cls._table_name} WHERE {' AND '.join(conditions)}"
            cursor = conn.execute(sql, values)
            
            results = []
            for row in cursor.fetchall():
                row_kwargs = {name: row[i] for i, name in enumerate(cls._fields)}
                results.append(cls(**row_kwargs))
            
            return results
        
        def __repr__(self):
            fields_str = ', '.join([f"{k}={v}" for k, v in self.__dict__.items()])
            return f"{self.__class__.__name__}({fields_str})"

# 使用示例
def test_simple_orm():
    print("=== 简化版ORM测试 ===")
    
    # 定义模型
    class User(SimpleORM.Model):
        _table_name = "users"
        id = SimpleORM.IntegerField(primary_key=True)
        name = SimpleORM.TextField()
        email = SimpleORM.TextField()
        age = SimpleORM.IntegerField(default=0)
    
    class Post(SimpleORM.Model):
        id = SimpleORM.IntegerField(primary_key=True)
        title = SimpleORM.TextField()
        content = SimpleORM.TextField()
        author_id = SimpleORM.IntegerField()
    
    # 创建数据库连接
    conn = sqlite3.connect(':memory:')
    
    # 创建表
    User.create_table(conn)
    Post.create_table(conn)
    print(" 数据表创建完成")
    
    # 创建记录
    user1 = User(id=1, name="li", email="li@example.com", age=25)
    user1.save(conn)
    
    user2 = User(id=2, name="liu", email="liu@example.com", age=30)
    user2.save(conn)
    
    post1 = Post(id=1, title="Python教程", content="学习Python编程", author_id=1)
    post1.save(conn)
    
    post2 = Post(id=2, title="数据分析", content="数据科学入门", author_id=2)
    post2.save(conn)
    
    # 查询所有用户
    print("\n所有用户:")
    users = User.all(conn)
    for user in users:
        print(f"  {user}")
    
    # 条件查询
    print("\n年龄大于25的用户:")
    older_users = User.filter(conn, age=30)
    for user in older_users:
        print(f"  {user}")
    
    # 查询文章
    print("\n所有文章:")
    posts = Post.all(conn)
    for post in posts:
        print(f"  {post}")
    
    conn.close()
    print("\n ORM测试完成")

if __name__ == "__main__":
    test_simple_orm()

元类的最佳实践

class MetaclassBestPractices:
    """元类使用最佳实践"""
    @staticmethod
    def when_to_use_metaclasses():
        """何时使用元类"""
        print("=== 元类使用场景 ===")
        # 场景1: 单例模式
        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):
                self.connection_id = id(self)
        
        # 场景2: 注册模式
        class RegistryMeta(type):
            registry = {}   
            def __new__(mcs, name, bases, namespace):
                cls = super().__new__(mcs, name, bases, namespace)
                if hasattr(cls, 'register_name'):
                    mcs.registry[cls.register_name] = cls
                return cls
        class Handler(metaclass=RegistryMeta):
            pass 
        class UserHandler(Handler):
            register_name = 'user'
        class OrderHandler(Handler):
            register_name = 'order'
        print("注册的处理器:", RegistryMeta.registry)
        
        # 场景3: API包装
        class APIMeta(type):
            def __new__(mcs, name, bases, namespace):
                # 为所有方法添加日志
                for key, value in namespace.items():
                    if callable(value) and not key.startswith('_'):
                        namespace[key] = mcs.add_logging(value)
                
                return super().__new__(mcs, name, bases, namespace)
            
            @staticmethod
            def add_logging(func):
                def wrapper(*args, **kwargs):
                    print(f" 调用方法: {func.__name__}")
                    result = func(*args, **kwargs)
                    print(f" 方法完成: {func.__name__}")
                    return result
                return wrapper
        
        class APIClient(metaclass=APIMeta):
            def get_user(self, user_id):
                return f"User {user_id}"
            
            def create_order(self, data):
                return f"Order created: {data}"
        
        print("\n测试API客户端:")
        client = APIClient()
        client.get_user(123)
        client.create_order({"item": "laptop"})
    
    @staticmethod
    def metaclass_alternatives():
        """元类的替代方案"""
        print("\n=== 元类替代方案 ===")
        # 替代方案1: 类装饰器
        def singleton(cls):
            instances = {}
            def get_instance(*args, **kwargs):
                if cls not in instances:
                    instances[cls] = cls(*args, **kwargs)
                return instances[cls]
            return get_instance
        @singleton
        class ConfigManager:
            def __init__(self):
                self.config = {}
        # 替代方案2: __init_subclass__
        class BaseHandler:
            registry = {}
            
            def __init_subclass__(cls, register_name=None, **kwargs):
                super().__init_subclass__(**kwargs)
                if register_name:
                    cls.registry[register_name] = cls
        
        class PaymentHandler(BaseHandler, register_name='payment'):
            pass
        class EmailHandler(BaseHandler, register_name='email'):
            pass
        print("使用__init_subclass__的注册:", BaseHandler.registry)
        
        # 替代方案3: 描述符
        class LoggedMethod:
            def __init__(self, func):
                self.func = func    
            def __get__(self, instance, owner):
                if instance is None:
                    return self
                
                def wrapper(*args, **kwargs):
                    print(f" 调用方法: {self.func.__name__}")
                    result = self.func(instance, *args, **kwargs)
                    print(f" 方法完成: {self.func.__name__}")
                    return result        
                return wrapper
        
        class ServiceClient:
            @LoggedMethod
            def process_data(self, data):
                return f"处理数据: {data}"
        
        print("\n测试描述符方案:")
        service = ServiceClient()
        service.process_data("test data")

def test_best_practices():
    """测试最佳实践"""
    practices = MetaclassBestPractices()
    practices.when_to_use_metaclasses()
    practices.metaclass_alternatives()

test_best_practices()

描述符设计模式

class DescriptorPatterns:
    """描述符设计模式"""
    class ValidationMixin:
        """验证混入类""" 
        def __init__(self, *validators, **kwargs):
            self.validators = validators
            super().__init__(**kwargs)
        
        def validate(self, value):
            """执行所有验证器"""
            for validator in self.validators:
                validator(value)
            return value
    class TypedAttribute(ValidationMixin):
        """类型化属性"""
        def __init__(self, expected_type, *validators, default=None):
            self.expected_type = expected_type
            self.default = default
            self.data = {}
            super().__init__(*validators)
        
        def __set_name__(self, owner, name):
            self.name = name
        
        def __get__(self, instance, owner):
            if instance is None:
                return self
            return self.data.get(id(instance), self.default)
        
        def __set__(self, instance, value):
            # 类型检查
            if value is not None and not isinstance(value, self.expected_type):
                raise TypeError(f"{self.name} 必须是 {self.expected_type.__name__} 类型")
            # 执行验证
            if value is not None:
                value = self.validate(value)
            self.data[id(instance)] = value
    
    class ComputedAttribute:
        """计算属性"""
        def __init__(self, func, *dependencies):
            self.func = func
            self.dependencies = dependencies
            self.cache = {}
            self.cache_valid = {}
        
        def __set_name__(self, owner, name):
            self.name = name
            # 监听依赖属性的变化
            for dep in self.dependencies:
                self._setup_dependency_monitoring(owner, dep)
        
        def _setup_dependency_monitoring(self, owner, dep_name):
            """设置依赖监听"""
            # 这里简化实现,不在元类层面设置监听, 在实际使用中会在实例层面处理
            pass
        
        def __get__(self, instance, owner):
            if instance is None:
                return self
            instance_id = id(instance)

            # 检查缓存是否有效
            if instance_id in self.cache and self.cache_valid.get(instance_id, False):
                return self.cache[instance_id]
            # 重新计算
            value = self.func(instance)
            self.cache[instance_id] = value
            self.cache_valid[instance_id] = True
            return value
        
        def invalidate_cache(self, instance):
            """使缓存失效"""
            instance_id = id(instance)
            if instance_id in self.cache:
                self.cache_valid[instance_id] = False
    
    class ObservableAttribute:
        """可观察属性"""
        def __init__(self, default=None):
            self.default = default
            self.data = {}
            self.observers = {}
        
        def __set_name__(self, owner, name):
            self.name = name
        
        def __get__(self, instance, owner):
            if instance is None:
                return self
            return self.data.get(id(instance), self.default)
        
        def __set__(self, instance, value):
            old_value = self.data.get(id(instance), self.default)
            self.data[id(instance)] = value
            
            # 通知观察者
            self._notify_observers(instance, old_value, value)
        
        def observe(self, instance, callback):
            """添加观察者"""
            instance_id = id(instance)
            if instance_id not in self.observers:
                self.observers[instance_id] = []
            self.observers[instance_id].append(callback)
        
        def _notify_observers(self, instance, old_value, new_value):
            """通知观察者"""
            instance_id = id(instance)
            if instance_id in self.observers:
                for callback in self.observers[instance_id]:
                    callback(instance, self.name, old_value, new_value)

def test_descriptor_patterns():
    print("=== 描述符设计模式测试 ===")
    # 定义验证器
    def positive(value):
        if value <= 0:
            raise ValueError("值必须为正数")
    
    def max_length(length):
        def validator(value):
            if len(str(value)) > length:
                raise ValueError(f"长度不能超过 {length}")
        return validator
    
    # 使用描述符模式的类
    class Product:
        name = DescriptorPatterns.TypedAttribute(str, max_length(50), default="")
        price = DescriptorPatterns.TypedAttribute(float, positive, default=0.0)
        quantity = DescriptorPatterns.TypedAttribute(int, positive, default=0)
        
        # 计算属性
        def _calculate_total(self):
            return self.price * self.quantity
        total = DescriptorPatterns.ComputedAttribute(_calculate_total, 'price', 'quantity')
        
        # 可观察属性
        status = DescriptorPatterns.ObservableAttribute("available")
        
        def __init__(self, name="", price=0.0, quantity=0):
            self.name = name
            self.price = price
            self.quantity = quantity
            
            # 添加状态观察者
            def status_changed(instance, attr_name, old_value, new_value):
                print(f" 产品状态变化: {old_value} -> {new_value}")
            type(self).status.observe(self, status_changed)
        
        def __setattr__(self, name, value):
            # 手动处理计算属性缓存失效
            if name in ['price', 'quantity'] and hasattr(type(self), 'total'):
                type(self).total.invalidate_cache(self)
            super().__setattr__(name, value)
    
    print("\n1. 创建产品:")
    product = Product("笔记本电脑", 5000.0, 2)
    print(f"产品: {product.name}, 价格: {product.price}, 数量: {product.quantity}")
    print(f"总价: {product.total}")
    
    print("\n2. 修改属性:")
    product.price = 4500.0
    print(f"修改价格后总价: {product.total}")
    
    product.quantity = 3
    print(f"修改数量后总价: {product.total}")
    
    print("\n3. 状态变化:")
    product.status = "out_of_stock"
    product.status = "available"
    
    print("\n4. 验证测试:")
    try:
        product.price = -100.0  # 负数价格
    except ValueError as e:
        print(f"验证错误: {e}")
    
    try:
        product.name = "A" * 100  # 名称过长
    except ValueError as e:
        print(f"验证错误: {e}")

if __name__ == "__main__":
    test_descriptor_patterns()

您可能感兴趣的与本文相关的镜像

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值