Skip to content

📝 第9天:面向对象编程高级特性魔法练习 - 魔法师的进阶实战训练

🎉 恭喜你完成了面向对象编程高级特性的学习!现在是时候通过一些有趣的练习来巩固你的知识了。这些练习将帮助你更好地理解和应用类方法、静态方法、属性装饰器、描述符、多重继承、元编程和反射等高级特性。

🎯 练习目标

  • 熟练掌握类方法、静态方法和属性装饰器的使用
  • 理解并应用描述符来定制属性访问行为
  • 掌握多重继承和Mixin模式
  • 了解元编程的基本概念和应用
  • 能够使用反射机制在运行时操作对象

🔍 基础练习题

1. 温度转换器(属性装饰器练习)

任务: 创建一个Temperature类,使用属性装饰器实现摄氏度和华氏度之间的自动转换。

要求:

  • 实现celsiusfahrenheit两个属性,它们可以互相转换
  • 当设置其中一个属性时,另一个属性会自动更新
  • 添加适当的验证,确保温度值是有效的数字

示例:

python
temp = Temperature(celsius=25)
print(temp.celsius)  # 输出: 25.0
print(temp.fahrenheit)  # 输出: 77.0

temp.fahrenheit = 98.6
print(temp.celsius)  # 输出: 37.0
print(temp.fahrenheit)  # 输出: 98.6

2. 商品库存管理(类方法练习)

任务: 创建一个Product类,使用类方法来跟踪和管理所有产品的库存。

要求:

  • 实现类变量来跟踪所有产品的总数
  • 创建类方法来获取产品总数、查找产品和更新库存
  • 实现实例方法来增加或减少单个产品的库存

示例:

python
Product.add_product("手机", 100, 2999.0)
Product.add_product("笔记本电脑", 50, 5999.0)
print(f"总产品数: {Product.get_total_products()}")
product = Product.find_product("手机")
if product:
    product.reduce_stock(10)
    print(f"手机剩余库存: {product.stock}")

3. 验证器描述符(描述符练习)

任务: 创建几个描述符类来验证不同类型的属性。

要求:

  • 实现StringValidatorNumberValidatorEmailValidator描述符
  • 每个描述符应该能够验证属性值是否符合特定的规则
  • 在一个User类中使用这些描述符

示例:

python
class User:
    username = StringValidator("username", min_length=3, max_length=20)
    age = NumberValidator("age", min_value=18, max_value=120)
    email = EmailValidator("email")
    
    def __init__(self, username, age, email):
        self.username = username
        self.age = age
        self.email = email

user = User("john_doe", 25, "john.doe@example.com")
# user.username = "j"  # 会引发ValueError异常
# user.age = 16  # 会引发ValueError异常
# user.email = "invalid-email"  # 会引发ValueError异常

4. 动物模拟器(多重继承练习)

任务: 创建一个动物模拟器,使用多重继承来组合不同的特性。

要求:

  • 创建基础的Animal类和几个特性类(如CanFly, CanSwim, CanWalk
  • 通过多重继承创建具有多种特性的具体动物类(如Bird可以飞和走,Duck可以飞、走和游)
  • 确保方法解析顺序正确工作

示例:

python
bird = Bird("麻雀")
bird.fly()  # 输出: 麻雀正在飞行
bird.walk()  # 输出: 麻雀正在走路

duck = Duck("鸭子")
duck.fly()  # 输出: 鸭子正在飞行
duck.walk()  # 输出: 鸭子正在走路
duck.swim()  # 输出: 鸭子正在游泳

5. 反射式配置管理器(反射练习)

任务: 创建一个配置管理器,可以使用反射机制动态地设置和获取配置项。

要求:

  • 实现ConfigManager类,使用反射来管理配置项
  • 提供方法来设置、获取、检查和删除配置项
  • 支持从字典加载配置和导出配置到字典

示例:

python
config = ConfigManager()
config.set_config("database.url", "mongodb://localhost:27017")
config.set_config("database.username", "admin")
config.set_config("database.password", "password")

print(f"数据库URL: {config.get_config('database.url')}")
print(f"是否存在API密钥配置: {config.has_config('api.key')}")

# 导出配置到字典
config_dict = config.export_config()
print(f"配置字典: {config_dict}")

🚀 挑战题

1. 高级计算器(综合练习)

任务: 创建一个高级计算器,结合多种面向对象编程高级特性。

要求:

  • 使用Mixin模式添加日志、错误处理等功能
  • 使用描述符验证输入参数
  • 使用类方法实现常用的计算功能
  • 使用属性装饰器实现计算结果的缓存

提示:

  • 创建Calculator基类,实现基本的计算功能
  • 创建LoggingMixinErrorHandlingMixin等Mixin类
  • 创建NumberValidator描述符来验证输入参数
  • 使用@property装饰器实现结果缓存

2. ORM框架简化版(元编程练习)

任务: 创建一个简化版的ORM(对象关系映射)框架,使用元编程来动态创建模型类。

要求:

  • 实现一个Model基类,使用元类来处理表名、字段等信息
  • 实现字段描述符(如StringField, IntegerField, FloatField)来定义表的列
  • 提供基本的CRUD(创建、读取、更新、删除)操作
  • 支持简单的查询条件

提示:

  • 使用元类来拦截模型类的创建过程,收集字段信息
  • 实现字段描述符来处理字段值的存储和检索
  • 提供方法来将模型对象转换为数据库记录,以及从数据库记录创建模型对象

💡 部分参考答案

1. 温度转换器参考答案

python
class Temperature:
    def __init__(self, celsius=None, fahrenheit=None):
        if celsius is not None:
            self._celsius = float(celsius)
        elif fahrenheit is not None:
            self._celsius = (float(fahrenheit) - 32) * 5 / 9
        else:
            raise ValueError("必须提供摄氏度或华氏度值")
    
    @property
    def celsius(self):
        return self._celsius
    
    @celsius.setter
    def celsius(self, value):
        try:
            self._celsius = float(value)
        except (TypeError, ValueError):
            raise ValueError("温度必须是有效的数字")
    
    @property
    def fahrenheit(self):
        return self._celsius * 9 / 5 + 32
    
    @fahrenheit.setter
    def fahrenheit(self, value):
        try:
            self._celsius = (float(value) - 32) * 5 / 9
        except (TypeError, ValueError):
            raise ValueError("温度必须是有效的数字")

2. 商品库存管理参考答案

python
class Product:
    _products = {}
    _total_count = 0
    
    def __init__(self, name, stock, price):
        self.name = name
        self.stock = stock
        self.price = price
    
    @classmethod
    def add_product(cls, name, stock, price):
        """添加新商品"""
        if name in cls._products:
            raise ValueError(f"商品'{name}'已存在")
        product = cls(name, stock, price)
        cls._products[name] = product
        cls._total_count += 1
        return product
    
    @classmethod
    def get_total_products(cls):
        """获取商品总数"""
        return cls._total_count
    
    @classmethod
    def find_product(cls, name):
        """查找商品"""
        return cls._products.get(name)
    
    def increase_stock(self, amount):
        """增加库存"""
        if amount < 0:
            raise ValueError("增加的数量不能为负数")
        self.stock += amount
    
    def reduce_stock(self, amount):
        """减少库存"""
        if amount < 0:
            raise ValueError("减少的数量不能为负数")
        if amount > self.stock:
            raise ValueError("库存不足")
        self.stock -= amount

3. 验证器描述符参考答案

python
class StringValidator:
    def __init__(self, name, min_length=0, max_length=None):
        self.name = name
        self.min_length = min_length
        self.max_length = max_length
    
    def __get__(self, instance, owner):
        if instance is None:
            return self
        return instance.__dict__.get(self.name, "")
    
    def __set__(self, instance, value):
        if not isinstance(value, str):
            raise TypeError(f"{self.name}必须是字符串类型")
        if len(value) < self.min_length:
            raise ValueError(f"{self.name}长度不能小于{self.min_length}")
        if self.max_length is not None and len(value) > self.max_length:
            raise ValueError(f"{self.name}长度不能大于{self.max_length}")
        instance.__dict__[self.name] = value

class NumberValidator:
    def __init__(self, name, min_value=None, max_value=None):
        self.name = name
        self.min_value = min_value
        self.max_value = max_value
    
    def __get__(self, instance, owner):
        if instance is None:
            return self
        return instance.__dict__.get(self.name, 0)
    
    def __set__(self, instance, value):
        try:
            value = float(value)
        except (TypeError, ValueError):
            raise TypeError(f"{self.name}必须是数字类型")
        if self.min_value is not None and value < self.min_value:
            raise ValueError(f"{self.name}不能小于{self.min_value}")
        if self.max_value is not None and value > self.max_value:
            raise ValueError(f"{self.name}不能大于{self.max_value}")
        instance.__dict__[self.name] = value

class EmailValidator:
    def __init__(self, name):
        self.name = name
    
    def __get__(self, instance, owner):
        if instance is None:
            return self
        return instance.__dict__.get(self.name, "")
    
    def __set__(self, instance, value):
        if not isinstance(value, str):
            raise TypeError(f"{self.name}必须是字符串类型")
        if "@" not in value:
            raise ValueError(f"{self.name}不是有效的邮箱地址")
        instance.__dict__[self.name] = value

class User:
    username = StringValidator("username", min_length=3, max_length=20)
    age = NumberValidator("age", min_value=18, max_value=120)
    email = EmailValidator("email")
    
    def __init__(self, username, age, email):
        self.username = username
        self.age = age
        self.email = email

4. 动物模拟器参考答案

python
class Animal:
    def __init__(self, name):
        self.name = name
    
    def speak(self):
        print(f"{self.name} 发出了声音")

class CanFly:
    def fly(self):
        print(f"{self.name} 正在飞行")

class CanSwim:
    def swim(self):
        print(f"{self.name} 正在游泳")

class CanWalk:
    def walk(self):
        print(f"{self.name} 正在走路")

class Bird(Animal, CanFly, CanWalk):
    def speak(self):
        print(f"{self.name} 叽叽喳喳地叫")

class Fish(Animal, CanSwim):
    def speak(self):
        print(f"{self.name} 没有发出声音")

class Duck(Animal, CanFly, CanSwim, CanWalk):
    def speak(self):
        print(f"{self.name} 呱呱地叫")

5. 反射式配置管理器参考答案

python
class ConfigManager:
    def __init__(self):
        self._config = {}
    
    def set_config(self, key, value):
        """设置配置项"""
        # 支持嵌套配置,如 "database.url"
        parts = key.split(".")
        config = self._config
        
        # 遍历除最后一个部分外的所有部分
        for part in parts[:-1]:
            if part not in config or not isinstance(config[part], dict):
                config[part] = {}
            config = config[part]
        
        # 设置最后一个部分的值
        config[parts[-1]] = value
    
    def get_config(self, key, default=None):
        """获取配置项"""
        parts = key.split(".")
        config = self._config
        
        # 遍历所有部分
        for part in parts:
            if part not in config or not isinstance(config, dict):
                return default
            config = config[part]
        
        return config
    
    def has_config(self, key):
        """检查配置项是否存在"""
        parts = key.split(".")
        config = self._config
        
        # 遍历所有部分
        for part in parts:
            if part not in config or not isinstance(config, dict):
                return False
            config = config[part]
        
        return True
    
    def remove_config(self, key):
        """删除配置项"""
        parts = key.split(".")
        config = self._config
        parents = []
        
        # 遍历所有部分并记录父配置
        for part in parts[:-1]:
            if part not in config or not isinstance(config, dict):
                return False
            parents.append((config, part))
            config = config[part]
        
        # 删除配置项
        if parts[-1] in config:
            del config[parts[-1]]
            
            # 清理空的父配置
            for parent, part in reversed(parents):
                if not parent[part]:
                    del parent[part]
            
            return True
        
        return False
    
    def export_config(self):
        """导出配置到字典"""
        return self._config.copy()
    
    def load_config(self, config_dict):
        """从字典加载配置"""
        # 递归地将字典中的所有配置项添加到配置管理器中
        def _load_dict(prefix, d):
            for key, value in d.items():
                full_key = f"{prefix}.{key}" if prefix else key
                if isinstance(value, dict):
                    _load_dict(full_key, value)
                else:
                    self.set_config(full_key, value)
        
        _load_dict("", config_dict)

🎯 练习总结

通过这些练习,你应该能够:

  1. 熟练使用类方法、静态方法和属性装饰器来增强类的功能
  2. 理解并应用描述符来自定义属性访问行为
  3. 掌握多重继承和Mixin模式来组合不同的功能
  4. 了解元编程的基本概念和应用
  5. 使用反射机制在运行时操作对象

这些高级特性可以帮助你编写更加灵活、可维护和可扩展的代码。在实际项目中,合理地运用这些特性可以大大提高代码的质量和效率。

继续加油!下一课我们将学习Python的模块和包管理,敬请期待!🚀

© 2025 技术博客. All rights reserved by 老周有AI