类高级特性

深入探索Python类的魔法方法、元类、数据描述符等高级特性,构建强大的面向对象系统

魔法方法

元类

描述符

1. 魔法方法详解

魔法方法(Magic Methods)是以双下划线开头和结尾的特殊方法,它们让Python类能够支持内置操作。

小贴士:魔法方法让Python类更加Pythonic,能够自然地集成到Python生态系统中!

__init__ 和 __new__

class Person:
    def __new__(cls, name):
        print("创建实例")
        return super().__new__(cls)
    
    def __init__(self, name):
        print("初始化实例")
        self.name = name

__str__ 和 __repr__

class Book:
    def __init__(self, title, author):
        self.title = title
        self.author = author
    
    def __str__(self):
        return f"《{self.title}》- {self.author}"
    
    def __repr__(self):
        return f"Book('{self.title}', '{self.author}')"

__len__ 和 __getitem__

class ShoppingCart:
    def __init__(self):
        self.items = []
    
    def __len__(self):
        return len(self.items)
    
    def __getitem__(self, index):
        return self.items[index]

__call__ 方法

class Multiplier:
    def __init__(self, factor):
        self.factor = factor
    
    def __call__(self, value):
        return value * self.factor

完整示例:自定义列表类

class SmartList:
    """智能列表类,支持多种操作"""
    
    def __init__(self, items=None):
        self.items = items or []
    
    def __len__(self):
        return len(self.items)
    
    def __getitem__(self, index):
        return self.items[index]
    
    def __setitem__(self, index, value):
        self.items[index] = value
    
    def __delitem__(self, index):
        del self.items[index]
    
    def __iter__(self):
        return iter(self.items)
    
    def __contains__(self, item):
        return item in self.items
    
    def __add__(self, other):
        return SmartList(self.items + other.items)
    
    def __str__(self):
        return f"SmartList({self.items})"
    
    def __repr__(self):
        return f"SmartList({self.items})"
    
    def append(self, item):
        self.items.append(item)
    
    def extend(self, items):
        self.items.extend(items)

# 使用示例
numbers = SmartList([1, 2, 3])
print(len(numbers))  # 3
print(numbers[0])    # 1
numbers[0] = 10
print(numbers)       # SmartList([10, 2, 3])
print(2 in numbers)  # True

2. 属性描述符详解

描述符(Descriptor)是实现了特定协议的类,可以控制属性的访问、设置和删除。

注意事项:描述符是Python的高级特性,用于创建自定义的属性行为!

2.1 数据描述符

class ValidatedAttribute:
    """验证属性值的描述符"""
    
    def __init__(self, min_value=None, max_value=None):
        self.min_value = min_value
        self.max_value = max_value
        self._values = {}
    
    def __get__(self, instance, owner):
        if instance is None:
            return self
        return self._values.get(instance, None)
    
    def __set__(self, instance, value):
        if self.min_value is not None and value < self.min_value:
            raise ValueError(f"值必须大于等于 {self.min_value}")
        if self.max_value is not None and value > self.max_value:
            raise ValueError(f"值必须小于等于 {self.max_value}")
        self._values[instance] = value
    
    def __delete__(self, instance):
        if instance in self._values:
            del self._values[instance]

class Person:
    age = ValidatedAttribute(min_value=0, max_value=150)
    height = ValidatedAttribute(min_value=0, max_value=300)

# 使用示例
person = Person()
person.age = 25  # 正常
person.height = 175  # 正常
# person.age = -5  # 会抛出 ValueError

2.2 非数据描述符

class LazyProperty:
    """延迟计算属性描述符"""
    
    def __init__(self, func):
        self.func = func
    
    def __get__(self, instance, owner):
        if instance is None:
            return self
        value = self.func(instance)
        setattr(instance, self.func.__name__, value)
        return value

class Circle:
    def __init__(self, radius):
        self.radius = radius
    
    @LazyProperty
    def area(self):
        print("计算面积...")
        return 3.14159 * self.radius ** 2

# 使用示例
circle = Circle(5)
print(circle.area)  # 第一次计算
print(circle.area)  # 第二次直接使用缓存值

2.3 属性装饰器

class Temperature:
    """温度类,使用属性装饰器"""
    
    def __init__(self, celsius=0):
        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
    
    @fahrenheit.setter
    def fahrenheit(self, value):
        """设置华氏度"""
        self.celsius = (value - 32) * 5/9
    
    @property
    def kelvin(self):
        """获取开尔文温度"""
        return self._celsius + 273.15

# 使用示例
temp = Temperature(25)
print(temp.celsius)     # 25
print(temp.fahrenheit)  # 77.0
print(temp.kelvin)      # 298.15

temp.fahrenheit = 100
print(temp.celsius)     # 37.77777777777778

3. 继承与多态高级

3.1 多重继承与MRO

class Animal:
    def speak(self):
        return "动物叫声"

class Flyer:
    def fly(self):
        return "我可以飞"

class Swimmer:
    def swim(self):
        return "我可以游泳"

class Duck(Animal, Flyer, Swimmer):
    def speak(self):
        return "嘎嘎"
    
    def __str__(self):
        return "鸭子"

# 使用示例
duck = Duck()
print(duck.speak())  # 嘎嘎
print(duck.fly())    # 我可以飞
print(duck.swim())   # 我可以游泳

# 查看方法解析顺序
print(Duck.__mro__)
# (, , 
#  , , )

3.2 抽象基类

from abc import ABC, abstractmethod

class Shape(ABC):
    """抽象形状类"""
    
    @abstractmethod
    def area(self):
        """计算面积"""
        pass
    
    @abstractmethod
    def perimeter(self):
        """计算周长"""
        pass
    
    def __str__(self):
        return f"形状: {self.__class__.__name__}"

class Rectangle(Shape):
    def __init__(self, width, height):
        self.width = width
        self.height = height
    
    def area(self):
        return self.width * self.height
    
    def perimeter(self):
        return 2 * (self.width + self.height)

class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius
    
    def area(self):
        return 3.14159 * self.radius ** 2
    
    def perimeter(self):
        return 2 * 3.14159 * self.radius

# 使用示例
shapes = [Rectangle(5, 3), Circle(4)]
for shape in shapes:
    print(f"{shape}: 面积={shape.area():.2f}, 周长={shape.perimeter():.2f}")

3.3 组合模式

class File:
    def __init__(self, name, size):
        self.name = name
        self.size = size
    
    def get_size(self):
        return self.size

class Directory:
    def __init__(self, name):
        self.name = name
        self.contents = []
    
    def add(self, item):
        self.contents.append(item)
    
    def remove(self, item):
        self.contents.remove(item)
    
    def get_size(self):
        return sum(item.get_size() for item in self.contents)

# 使用示例
root = Directory("根目录")
docs = Directory("文档")

docs.add(File("报告.txt", 1024))
docs.add(File("笔记.txt", 512))
root.add(docs)
root.add(File("程序.py", 2048))

print(f"总大小: {root.get_size()} 字节")  # 3584

4. 元类基础

元类(Metaclass)是创建类的类,它们控制类的创建过程。

注意事项:元类是Python的极高阶特性,一般只在框架开发中使用!

4.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)
        print(f"创建数据库连接: {self.connection_id}")

# 使用示例
db1 = DatabaseConnection()
db2 = DatabaseConnection()
print(db1 is db2)  # True,只有一个实例

4.2 自动注册类

class AutoRegisterMeta(type):
    """自动注册类的元类"""
    registry = {}
    
    def __new__(cls, name, bases, attrs):
        new_class = super().__new__(cls, name, bases, attrs)
        cls.registry[name.lower()] = new_class
        return new_class

class BaseCommand(metaclass=AutoRegisterMeta):
    def execute(self):
        pass

class CreateCommand(BaseCommand):
    def execute(self):
        return "创建操作"

class DeleteCommand(BaseCommand):
    def execute(self):
        return "删除操作"

# 使用示例
print(AutoRegisterMeta.registry)
# {'basecommand': , 
#  'createcommand': , 
#  'deletecommand': }

故事化案例:智能游戏引擎

场景:小李是一名游戏开发者,正在开发一个复杂的角色扮演游戏。他需要创建一个灵活的游戏引擎,支持不同类型的游戏角色、装备系统和技能系统。让我们用类的高级特性来实现这个强大的游戏引擎!

1. 游戏角色系统

class CharacterMeta(type):
    """角色元类,自动注册角色类型"""
    
    def __new__(cls, name, bases, attrs):
        new_class = super().__new__(cls, name, bases, attrs)
        if not hasattr(cls, 'registry'):
            cls.registry = {}
        cls.registry[name.lower()] = new_class
        return new_class

class GameCharacter(metaclass=CharacterMeta):
    """游戏角色基类"""
    
    def __init__(self, name, level=1):
        self.name = name
        self.level = level
        self._health = 100
        self._mana = 50
        self._experience = 0
    
    @property
    def health(self):
        return self._health
    
    @health.setter
    def health(self, value):
        self._health = max(0, min(value, self.max_health))
    
    @property
    def mana(self):
        return self._mana
    
    @mana.setter
    def mana(self, value):
        self._mana = max(0, min(value, self.max_mana))
    
    @property
    def max_health(self):
        return 100 + self.level * 10
    
    @property
    def max_mana(self):
        return 50 + self.level * 5
    
    def __str__(self):
        return f"{self.__class__.__name__}: {self.name} (等级{self.level})"
    
    def __repr__(self):
        return f"{self.__class__.__name__}('{self.name}', {self.level})"

class Warrior(GameCharacter):
    def __init__(self, name, level=1):
        super().__init__(name, level)
        self.strength = 15 + level * 3
        self.defense = 12 + level * 2
    
    def attack(self):
        return f"{self.name} 使用剑击造成 {self.strength} 点伤害"

class Mage(GameCharacter):
    def __init__(self, name, level=1):
        super().__init__(name, level)
        self.intelligence = 18 + level * 4
        self.mana *= 1.5
    
    def cast_spell(self):
        if self.mana >= 20:
            self.mana -= 20
            return f"{self.name} 释放火球术造成 {self.intelligence * 1.5} 点魔法伤害"
        return f"{self.name} 魔力不足,无法施法"

class Archer(GameCharacter):
    def __init__(self, name, level=1):
        super().__init__(name, level)
        self.agility = 16 + level * 3.5
        self.critical_chance = 0.2 + level * 0.02
    
    def shoot_arrow(self):
        damage = self.agility * 1.2
        if random.random() < self.critical_chance:
            damage *= 2
            return f"{self.name} 射出暴击箭造成 {damage} 点伤害!"
        return f"{self.name} 射出箭矢造成 {damage} 点伤害"

# 使用示例
warrior = Warrior("亚瑟", 5)
mage = Mage("梅林", 4)
archer = Archer("罗宾", 3)

print(warrior)
print(mage)
print(archer)

print(CharacterMeta.registry)
# 查看所有注册的角色类型

2. 装备系统

class EquipmentMeta(type):
    """装备元类,管理装备类型"""
    
    def __new__(cls, name, bases, attrs):
        new_class = super().__new__(cls, name, bases, attrs)
        if not hasattr(cls, 'equipment_types'):
            cls.equipment_types = {}
        cls.equipment_types[name.lower()] = new_class
        return new_class

class Equipment(metaclass=EquipmentMeta):
    """装备基类"""
    
    def __init__(self, name, rarity="普通"):
        self.name = name
        self.rarity = rarity
        self._enhancement_level = 0
    
    @property
    def enhancement_level(self):
        return self._enhancement_level
    
    @enhancement_level.setter
    def enhancement_level(self, value):
        if 0 <= value <= 15:
            self._enhancement_level = value
        else:
            raise ValueError("强化等级必须在0-15之间")
    
    def __str__(self):
        rarity_colors = {
            "普通": "白色",
            "稀有": "蓝色",
            "史诗": "紫色",
            "传说": "橙色"
        }
        return f"{rarity_colors.get(self.rarity, '未知')} {self.rarity} {self.name} +{self.enhancement_level}"
    
    def __add__(self, other):
        """装备合成"""
        if isinstance(other, Equipment) and self.__class__ == other.__class__:
            new_name = f"强化{self.name}"
            new_equipment = self.__class__(new_name, self.rarity)
            new_equipment.enhancement_level = min(self.enhancement_level + 1, 15)
            return new_equipment
        raise TypeError("只能合成相同类型的装备")

class Weapon(Equipment):
    def __init__(self, name, attack_power, rarity="普通"):
        super().__init__(name, rarity)
        self.base_attack = attack_power
        self.weapon_type = "武器"
    
    @property
    def total_attack(self):
        return self.base_attack * (1 + self.enhancement_level * 0.1)

class Armor(Equipment):
    def __init__(self, name, defense_power, rarity="普通"):
        super().__init__(name, rarity)
        self.base_defense = defense_power
        self.armor_type = "防具"
    
    @property
    def total_defense(self):
        return self.base_defense * (1 + self.enhancement_level * 0.08)

class Accessory(Equipment):
    def __init__(self, name, special_effect, rarity="普通"):
        super().__init__(name, rarity)
        self.special_effect = special_effect
        self.accessory_type = "饰品"

# 使用示例
sword = Weapon("长剑", 100, "史诗")
shield = Armor("圆盾", 50, "稀有")
ring = Accessory("力量戒指", "增加10%攻击力")

print(sword)
print(shield)
print(ring)

# 装备合成
enhanced_sword = sword + sword
print(f"合成后: {enhanced_sword}")
print(f"攻击力: {enhanced_sword.total_attack}")

3. 技能系统

class SkillSystem:
    """技能系统管理器"""
    
    def __init__(self):
        self.skills = {}
    
    def register_skill(self, skill_class):
        """注册技能类"""
        self.skills[skill_class.__name__.lower()] = skill_class
    
    def create_skill(self, skill_name, *args, **kwargs):
        """创建技能实例"""
        if skill_name.lower() in self.skills:
            return self.skills[skill_name.lower()](*args, **kwargs)
        raise ValueError(f"未知技能: {skill_name}")

class Skill:
    """技能基类"""
    
    def __init__(self, name, mana_cost, cooldown):
        self.name = name
        self.mana_cost = mana_cost
        self.cooldown = cooldown
        self._current_cooldown = 0
    
    @property
    def is_ready(self):
        return self._current_cooldown <= 0
    
    def use(self, caster):
        """使用技能"""
        if not self.is_ready:
            return f"技能 {self.name} 冷却中 ({self._current_cooldown}回合)"
        
        if caster.mana < self.mana_cost:
            return f"魔力不足,无法使用 {self.name}"
        
        caster.mana -= self.mana_cost
        self._current_cooldown = self.cooldown
        return self.execute(caster)
    
    def execute(self, caster):
        """技能执行逻辑(子类实现)"""
        raise NotImplementedError
    
    def tick(self):
        """每回合更新"""
        if self._current_cooldown > 0:
            self._current_cooldown -= 1

class Fireball(Skill):
    def __init__(self):
        super().__init__("火球术", 20, 2)
    
    def execute(self, caster):
        damage = caster.intelligence * 1.5
        return f"{caster.name} 释放火球术造成 {damage} 点魔法伤害"

class Heal(Skill):
    def __init__(self):
        super().__init__("治疗术", 15, 3)
    
    def execute(self, caster):
        heal_amount = caster.intelligence * 2
        caster.health += heal_amount
        return f"{caster.name} 使用治疗术恢复 {heal_amount} 点生命值"

class Shield(Skill):
    def __init__(self):
        super().__init__("护盾术", 10, 4)
    
    def execute(self, caster):
        shield_amount = caster.defense * 1.2
        return f"{caster.name} 激活护盾,获得 {shield_amount} 点护盾值"

# 使用示例
skill_system = SkillSystem()
skill_system.register_skill(Fireball)
skill_system.register_skill(Heal)
skill_system.register_skill(Shield)

mage = Mage("艾莉娅", 10)
fireball = skill_system.create_skill("fireball")
heal = skill_system.create_skill("heal")

print(fireball.use(mage))
print(heal.use(mage))

# 模拟回合
for i in range(5):
    fireball.tick()
    if i == 2:
        print(fireball.use(mage))  # 冷却结束

高级练习题(共5个)

练习题1:观察者模式

使用描述符实现观察者模式,当对象属性发生变化时自动通知观察者。

# 参考答案
class Observable:
    def __init__(self):
        self._observers = []
    
    def add_observer(self, observer):
        self._observers.append(observer)
    
    def notify_observers(self, name, old_value, new_value):
        for observer in self._observers:
            observer.update(name, old_value, new_value)

class ObservableAttribute:
    def __init__(self, name):
        self.name = name
        self._values = {}
    
    def __get__(self, instance, owner):
        if instance is None:
            return self
        return self._values.get(instance, None)
    
    def __set__(self, instance, value):
        old_value = self._values.get(instance, None)
        self._values[instance] = value
        if hasattr(instance, 'notify_observers'):
            instance.notify_observers(self.name, old_value, value)

class GameCharacter(Observable):
    health = ObservableAttribute('health')
    mana = ObservableAttribute('mana')
    
    def __init__(self, name):
        super().__init__()
        self.name = name

class HealthBar:
    def update(self, name, old_value, new_value):
        if name == 'health':
            print(f"血量更新: {old_value} -> {new_value}")

# 使用示例
character = GameCharacter("英雄")
health_bar = HealthBar()
character.add_observer(health_bar)
character.health = 100
character.health = 80

练习题2:状态模式

实现状态模式,让游戏角色能够根据当前状态改变行为。

# 参考答案
class CharacterState:
    def handle_attack(self, character):
        pass

class NormalState(CharacterState):
    def handle_attack(self, character):
        return f"{character.name} 正常攻击"

class BuffedState(CharacterState):
    def handle_attack(self, character):
        return f"{character.name} 强化攻击造成双倍伤害"

class StunnedState(CharacterState):
    def handle_attack(self, character):
        return f"{character.name} 被眩晕,无法攻击"

class GameCharacter:
    def __init__(self, name):
        self.name = name
        self._state = NormalState()
    
    @property
    def state(self):
        return self._state
    
    @state.setter
    def state(self, new_state):
        self._state = new_state
    
    def attack(self):
        return self._state.handle_attack(self)

# 使用示例
character = GameCharacter("战士")
print(character.attack())
character.state = BuffedState()
print(character.attack())
character.state = StunnedState()
print(character.attack())

练习题3:策略模式

创建策略模式,让游戏角色能够动态切换战斗策略。

# 参考答案
from abc import ABC, abstractmethod

class AttackStrategy(ABC):
    @abstractmethod
    def calculate_damage(self, character):
        pass

class MeleeStrategy(AttackStrategy):
    def calculate_damage(self, character):
        return character.strength * 1.2

class MagicStrategy(AttackStrategy):
    def calculate_damage(self, character):
        return character.intelligence * 1.5

class RangedStrategy(AttackStrategy):
    def calculate_damage(self, character):
        return character.agility * 1.3

class GameCharacter:
    def __init__(self, name, strength=10, intelligence=10, agility=10):
        self.name = name
        self.strength = strength
        self.intelligence = intelligence
        self.agility = agility
        self.strategy = MeleeStrategy()
    
    def set_strategy(self, strategy):
        self.strategy = strategy
    
    def attack(self):
        damage = self.strategy.calculate_damage(self)
        return f"{self.name} 使用 {self.strategy.__class__.__name__} 造成 {damage} 点伤害"

# 使用示例
character = GameCharacter("英雄")
print(character.attack())
character.set_strategy(MagicStrategy())
print(character.attack())

练习题4:工厂模式

实现工厂模式,动态创建不同类型的游戏对象。

# 参考答案
class GameObjectFactory:
    _creators = {}
    
    @classmethod
    def register(cls, name):
        def decorator(creator_class):
            cls._creators[name] = creator_class
            return creator_class
        return decorator
    
    @classmethod
    def create(cls, name, *args, **kwargs):
        if name in cls._creators:
            return cls._creators[name](*args, **kwargs)
        raise ValueError(f"未知对象类型: {name}")

@GameObjectFactory.register("enemy")
class Enemy:
    def __init__(self, name, health):
        self.name = name
        self.health = health

@GameObjectFactory.register("item")
class Item:
    def __init__(self, name, value):
        self.name = name
        self.value = value

@GameObjectFactory.register("npc")
class NPC:
    def __init__(self, name, dialogue):
        self.name = name
        self.dialogue = dialogue

# 使用示例
enemy = GameObjectFactory.create("enemy", "哥布林", 50)
item = GameObjectFactory.create("item", "生命药水", 100)
npc = GameObjectFactory.create("npc", "村长", "欢迎来到村庄!")

练习题5:装饰器模式

实现装饰器模式,动态为游戏角色添加额外能力。

# 参考答案
class CharacterDecorator:
    def __init__(self, character):
        self.character = character
    
    def attack(self):
        return self.character.attack()

class FireEnchantDecorator(CharacterDecorator):
    def attack(self):
        base_attack = self.character.attack()
        return f"{base_attack} 并附加火焰伤害"

class IceEnchantDecorator(CharacterDecorator):
    def attack(self):
        base_attack = self.character.attack()
        return f"{base_attack} 并附加冰霜伤害"

class SpeedBoostDecorator(CharacterDecorator):
    def attack(self):
        base_attack = self.character.attack()
        return f"{base_attack} (速度提升)"

# 使用示例
warrior = Warrior("战士", 10)
decorated_warrior = FireEnchantDecorator(
    SpeedBoostDecorator(warrior)
)
print(decorated_warrior.attack())