# GESP等级：三级 | GESP Python 三级考点

"""
================================================================================
 挑战2进阶 ★★+ — 配置继承与合并（dict + set 深度应用）
================================================================================

  场景：
    在挑战2的基础上，引入「配置继承」机制：
    - 画笔可以继承另一个画笔的配置
    - 支持单继承链
    - 用 set 检测循环继承
    - 用 dict 解析继承链上的最终配置

  知识点：
    - dict 的 MRO（方法解析顺序）思维——在配置继承中的应用
    - set 检测循环引用
    - 递归/迭代解析继承链
================================================================================
"""
from pprint import pprint

print("=" * 60)
print("挑战2进阶 ★★+ — 配置继承与合并")
print("=" * 60)

# ========== 1. 定义带继承的画笔配置 ==========
# 每个画笔可以指定 "_extends" 字段表示继承自哪个画笔
pen_defs = {
    "base": {
        "color": "black",
        "width": 2,
        "opacity": 1.0,
        "shape": "round",
    },
    "thick_pen": {
        "_extends": "base",
        "width": 10,
        "shape": "square",
    },
    "red_thick_pen": {
        "_extends": "thick_pen",
        "color": "red",
    },
    "transparent_pen": {
        "_extends": "base",
        "opacity": 0.3,
    },
    "red_transparent_pen": {
        "_extends": "transparent_pen",
        "color": "red",
    },
    "ultimate_pen": {
        "_extends": "red_thick_pen",
        "width": 20,
        "opacity": 0.5,
    },
}

print("\n1. 画笔定义（含继承关系）：")
for name, cfg in pen_defs.items():
    ext = cfg.get("_extends", "无")
    overrides = {k: v for k, v in cfg.items() if not k.startswith("_")}
    print(f"   {name:20s} → 继承自 {ext:15s} → 覆盖：{overrides}")


# ========== 2. 解析继承链（迭代方式）==========
def resolve_chain(name: str, defs: dict) -> list:
    """
    解析继承链，从自身到最顶层祖先。
    用 set 检测循环继承。
    """
    chain = []
    visited = set()
    current = name

    while current:
        if current in visited:
            raise RecursionError(f"检测到循环继承：{current} 已在链中 {chain}")
        visited.add(current)

        cfg = defs.get(current)
        if cfg is None:
            raise KeyError(f"配置 '{current}' 未定义")

        chain.append(current)
        current = cfg.get("_extends")  # 获取父类名，None 则停止

    return chain


print("\n2. 继承链解析：")
for name in pen_defs:
    chain = resolve_chain(name, pen_defs)
    print(f"   {name:20s} → {' → '.join(chain)}")


# ========== 3. 合并继承链上的配置 ==========
def merge_config(name: str, defs: dict) -> dict:
    """
    合并继承链上所有配置：
    从祖先到自身依次合并，子类覆盖父类。
    """
    chain = resolve_chain(name, defs)
    result = {}

    # 从最顶层祖先开始合并
    for cls_name in reversed(chain):
        cfg = defs[cls_name]
        for key, val in cfg.items():
            if not key.startswith("_"):  # 跳过元字段
                result[key] = val

    return result


print("\n3. 解析后的最终配置：")
for name in pen_defs:
    final = merge_config(name, pen_defs)
    print(f"   {name:20s} → ", end="")
    pprint(final, indent=4)
    print()


# ========== 4. 循环继承检测 ==========
print("4. 循环继承检测：")
cyclic_defs = {
    "a": {"_extends": "b", "width": 1},
    "b": {"_extends": "c", "width": 2},
    "c": {"_extends": "a", "width": 3},  # a → b → c → a 循环！
}

try:
    resolve_chain("a", cyclic_defs)
except RecursionError as e:
    print(f"   ✓ 成功检测到循环继承：{e}")


# ========== 5. 批量解析与缓存 ==========
class ConfigResolver:
    """带缓存的配置解析器"""

    def __init__(self, defs: dict):
        self._defs = defs
        self._cache = {}  # name → merged_config

    def resolve(self, name: str) -> dict:
        """解析并缓存结果"""
        if name not in self._cache:
            self._cache[name] = merge_config(name, self._defs)
        return dict(self._cache[name])  # 返回副本

    def invalidate(self, name: str = None):
        """清除缓存"""
        if name:
            self._cache.pop(name, None)
        else:
            self._cache.clear()

    @property
    def cache_info(self) -> dict:
        """缓存统计"""
        return {
            "cached_items": len(self._cache),
            "cached_names": list(self._cache.keys()),
        }


resolver = ConfigResolver(pen_defs)
print("\n5. 使用带缓存的解析器：")
for name in ["base", "ultimate_pen", "red_transparent_pen"]:
    cfg = resolver.resolve(name)
    print(f"   {name:20s} → 已缓存：{name in resolver._cache}")

print(f"   缓存统计：{resolver.cache_info}")


# ========== 6. 对比继承前后的差异 ==========
print("\n6. 子类与父类的配置差异（set 运算）：")
for name in ["thick_pen", "red_thick_pen", "ultimate_pen"]:
    chain = resolve_chain(name, pen_defs)
    parent = chain[1] if len(chain) > 1 else None
    if parent:
        child_cfg = set(merge_config(name, pen_defs).items())
        parent_cfg = set(merge_config(parent, pen_defs).items())
        diff = child_cfg - parent_cfg
        print(f"   {name} 对比 {parent} 的差异：{dict(diff) if diff else '无差异'}")


# ========== 总结 ==========
print()
print(">>> 挑战2进阶 关键收获 <<<")
print("1. dict 的继承链解析 = MRO 思维的简化版")
print("2. set 是做循环检测的最优工具（O(1) 查重）")
print("3. 逐层合并（祖先→子类）实现配置继承")
print("4. 缓存（dict）避免重复解析，提升性能")
print("5. 集合运算快速对比父子配置差异")
