🌟特质构造器小妙招🌟

55 阅读2分钟

1️⃣ 设计目标:一句话说清楚 🤏

“让我像搭积木一样,把任意结构(dict / dataclass / JSON Schema)瞬间变成不可变对象,还带代码提示!”

微信图片_20251014151033_10_20.jpg

2️⃣ 懒人工厂代码(Python 3.10+)

from typing import Any, get_type_hints
import copy
import json

class特制构造器:
    """
    链式 · 类型安全 · 可冻结 · 可序列化
    """
    __slots__ = ("_data", "_frozen")

    def __init__(self, **kwargs):
        # 1. 注入默认骨架
        self._data = self._defaults() | kwargs
        # 2. 类型检查
        self._validate()
        self._frozen = False

    @classmethod
    def _defaults(cls) -> dict[str, Any]:
        """子类重写 = 声明默认字段"""
        return {}

    def _validate(self):
        """运行时类型检查"""
        hints = get_type_hints(self)
        for k, v in self._data.items():
            if (h := hints.get(k)) and not isinstance(v, h):
                raise TypeError(f"{k} 需要 {h},但给了 {type(v)}")

    # ——— 链式装配 ———
    def with_(self, **kwargs):
        """链式更新,返回新实例"""
        new = copy.deepcopy(self)
        new._data |= kwargs
        new._validate()
        return new

    # ——— 冻结 · 不可变 ———
    def freeze(self):
        """冻住,不许改"""
        self._frozen = True
        return self

    def __setattr__(self, key, value):
        if getattr(self, "_frozen", False):
            raise RuntimeError("实例已冻结 ❄️")
        super().__setattr__(key, value)

    # ——— 魔法方法 ———
    def __getattr__(self, item):
        try:
            return self._data[item]
        except KeyError:
            raise AttributeError(item) from None

    def __repr__(self):
        return f"{self.__class__.__name__}({self._data})"

    # ——— 序列化 ———
    def to_dict(self):
        return copy.deepcopy(self._data)

    def to_json(self, *, indent=2):
        return json.dumps(self._data, indent=indent, ensure_ascii=False)

# ——— 使用示例:定义你的“特制结构” ———
class 电竞主机(特制构造器):
    """来一台 2025 年最香配置"""
    @classmethod
    def _defaults(cls):
        return {
            "cpu": "R9-7950X3D",
            "gpu": "RTX4090D",
            "ram": 32,
            "ssd": 2000,
            "rgb": True,
        }

# ——— 实战:链式 + 冻结 + JSON ———
if __name__ == "__main__":
    pc = 电竞主机() \
         .with_(gpu="RTX5080", ram=64) \
         .freeze()

    print(pc)                      # 电竞主机({'cpu': 'R9-7950X3D', ...})
    print(pc.gpu)                  # RTX5080
    print(pc.to_json())            # 直接导出 JSON 给前端
    # pc.rgb = False               # RuntimeError: 实例已冻结 ❄️

3️⃣ 运行结果图位(文字版)

电竞主机({'cpu': 'R9-7950X3D', 'gpu': 'RTX5080', 'ram': 64, 'ssd': 2000, 'rgb': True})
RTX5080
{
  "cpu": "R9-7950X3D",
  "gpu": "RTX5080",
  "ram": 64,
  "ssd": 2000,
  "rgb": true
}

4️⃣ 特色拆解(表情包对照)

能力实现技巧表情包
默认骨架_defaults() 类方法“懒人骨架”🦴
类型检查get_type_hints+isinstance“安检门”🛂
链式更新with_(...) 返回深拷贝“乐高拼接”🧩
不可变__setattr__ 里抛异常“冰封王座”❄️
序列化json.dumps 深拷贝“一键发朋友圈”📸

5️⃣ 想再卷一点?给你 3 个进阶按钮 🚀

  1. 缓存哈希 → 重写 __hash__,让实例进 set/dict
  2. 可选 Pydantic → 把 _validate 换成 BaseModel.parse_obj
  3. 自动生成 → 读 JSON Schema 动态创建子类,“schema → 类” 秒变 TypeScript 体验

🎯 总结口诀(背它!)

“默认骨架 + 类型安检 + 链式 with + 冻结锁 + JSON 秒出”
从此构造对象不用写七行 __init__一口价,全带走🛒