Слайд 5: Декораторы классов и метаклассы

Теория: Декораторы классов

Декораторы классов позволяют модифицировать классы при их определении, а метаклассы управляют процессом создания классов.

1. Создание декоратора класса:

def register_artifact_set(cls):
    """Декоратор для регистрации набора артефактов в системе"""
    cls.registered = True
    ARTIFACT_SETS[cls.__name__] = cls
    return cls

@register_artifact_set
class GladiatorsFinale:
    """Набор артефактов 'Конец гладиатора'"""
    two_piece_bonus = "ATK +18%"
    four_piece_bonus = "Урон обычной атаки +35%"
    
def buff_required(method):
    """Декоратор для методов, требующих наличия баффа"""
    def wrapper(self, *args, **kwargs):
        if not self.has_buff_active():
            raise ValueError("Требуется активный бафф!")
        return method(self, *args, **kwargs)
    return wrapper

class Character:
    @buff_required
    def use_special_attack(self):
        return "Усиленная атака!"

2. Декораторы с параметрами:

def require_constellations(level: int):
    """Декоратор, проверяющий уровень созвездий"""
    def decorator(cls):
        cls.required_constellation = level
        original_init = cls.__init__
        
        def new_init(self, *args, **kwargs):
            if self.constellation_level < level:
                raise ValueError(
                    f"Требуется {level} созвездие!"
                )
            original_init(self, *args, **kwargs)
        
        cls.__init__ = new_init
        return cls
    return decorator

@require_constellations(4)
class ZhongliShieldBot:
    """Класс для Чжун Ли с фокусом на щиты"""
    def __init__(self, constellation_level: int):
        self.constellation_level = constellation_level

3. Метаклассы:

class ElementalMeta(type):
    """Метакласс для элементальных способностей"""
    
    def __new__(cls, name, bases, attrs):
        # Проверка наличия необходимых методов
        if 'elemental_skill' not in attrs:
            attrs['elemental_skill'] = lambda self: "Базовый навык"
            
        # Добавление служебных атрибутов
        attrs['element_applied'] = False
        attrs['element_gauge'] = 0
        
        return super().__new__(cls, name, bases, attrs)

class Character(metaclass=ElementalMeta):
    def __init__(self, name: str):
        self.name = name
        
    def apply_element(self, gauge: float):
        self.element_applied = True
        self.element_gauge = gauge

4. Атрибуты и методы метаклассов:

class ArtifactSetMeta(type):
    """Метакласс для наборов артефактов"""
    
    @classmethod
    def __prepare__(mcs, name, bases):
        """Подготовка пространства имён"""
        return {"__pieces__": []}
    
    def __new__(mcs, name, bases, attrs):
        """Создание нового класса"""
        # Проверка обязательных атрибутов
        if "two_piece_bonus" not in attrs:
            raise TypeError(
                f"Набор {name} должен иметь two_piece_bonus"
            )
        
        # Создание свойств для бонусов
        attrs["has_2_piece"] = property(
            lambda self: len(self.__pieces__) >= 2
        )
        attrs["has_4_piece"] = property(
            lambda self: len(self.__pieces__) >= 4
        )
        
        return super().__new__(mcs, name, bases, attrs)
    
    def __call__(cls, *args, **kwargs):
        """Создание экземпляра класса"""
        instance = super().__call__(*args, **kwargs)
        print(f"Создан набор артефактов {cls.__name__}")
        return instance

Важно помнить:

  • Декораторы классов выполняются при определении класса
  • Декораторы могут изменять как сам класс, так и его атрибуты
  • Метаклассы позволяют контролировать создание классов
  • __new__ создаёт класс, __prepare__ подготавливает пространство имён
  • __call__ вызывается при создании экземпляра класса

Задача: Система баффов и эффектов

Создайте систему для работы с баффами и эффектами персонажей:

Подсказка: Примеры реализации:

def track_buff_duration(cls):
    """Декоратор для отслеживания баффов"""
    original_methods = {}
    
    for name, method in cls.__dict__.items():
        if getattr(method, "is_buff", False):
            original_methods[name] = method
            
class BuffEffect(metaclass=BuffMeta):
    def __init__(self, duration: float):
        self.duration = duration
        self.start_time = time.time()
        
@buff("attack")
class NoblegeEffect(BuffEffect):
    """Эффект комплекта Благородный обет"""