You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为TypeScript动态创建的对象应用装饰器?

运行时动态创建带装饰器的类/对象解决方案

核心思路

别直接创建对象,先基于你的动态描述构建带装饰器的类——因为装饰器本质是作用于类或类成员的语法糖,先建类再实例化,才能完全复现源码定义类的行为。

具体实现步骤

1. 定义你的动态描述结构

假设你已经把类的元信息存在这样的字典里(可根据实际需求调整字段):

# 示例动态描述:包含类名、类装饰器、属性/方法及其装饰器
class_meta = {
    "class_name": "User",
    "class_decorators": [validate_class, log_instantiation],
    "members": {
        "username": {
            "type": "property",
            "getter": lambda self: self._username,
            "setter": lambda self, val: setattr(self, "_username", val.strip()),
            "decorators": [validate_username]
        },
        "get_full_name": {
            "type": "method",
            "func": lambda self: f"{self.first_name} {self.last_name}",
            "decorators": [cache_result]
        },
        "count": {
            "type": "class_attr",
            "value": 0,
            "decorators": [readonly]
        }
    }
}

2. 写一个通用的装饰器应用工具

用来批量给目标(类、方法、属性)按正确顺序应用装饰器:

def apply_decorators(target, decorators):
    # 装饰器顺序和源码一致:@a @b 等价于 a(b(target)),所以倒序遍历
    for dec in reversed(decorators):
        target = dec(target)
    return target

3. 动态构建类成员

逐个处理每个属性/方法,应用对应的装饰器:

class_members = {}

for name, meta in class_meta["members"].items():
    if meta["type"] == "property":
        # 处理property类型的属性:先装饰getter,再添加setter
        getter = apply_decorators(meta["getter"], meta["decorators"])
        prop = property(getter)
        if "setter" in meta:
            setter = apply_decorators(meta["setter"], meta.get("setter_decorators", []))
            prop = prop.setter(setter)
        class_members[name] = prop
    elif meta["type"] == "method":
        # 处理普通方法、类方法、静态方法
        decorated_func = apply_decorators(meta["func"], meta["decorators"])
        class_members[name] = decorated_func
    elif meta["type"] == "class_attr":
        # 处理类属性
        class_members[name] = apply_decorators(meta["value"], meta["decorators"])

4. 动态创建类并应用类装饰器

用Python内置的type函数创建原始类,再给类本身应用装饰器:

# 创建原始类:参数依次是类名、父类元组、类成员字典
raw_class = type(class_meta["class_name"], (object,), class_members)
# 给类应用装饰器
final_class = apply_decorators(raw_class, class_meta["class_decorators"])
# 实例化对象
dynamic_obj = final_class()

5. 验证和源码类的一致性

对比动态创建的对象和源码硬编码的类实例:

# 源码定义的类,用来对比
@validate_class
@log_instantiation
class StaticUser:
    count = readonly(0)
    
    @validate_username
    @property
    def username(self):
        return self._username
    
    @username.setter
    def username(self, val):
        self._username = val.strip()
    
    @cache_result
    def get_full_name(self):
        return f"{self.first_name} {self.last_name}"

static_obj = StaticUser()
# 验证行为一致
dynamic_obj.username = "  test_user  "
static_obj.username = "  test_user  "
assert dynamic_obj.username == static_obj.username
assert dynamic_obj.count == static_obj.count

关键注意事项

  • 装饰器顺序不能乱:源码中写在上面的装饰器要最后应用,比如@a @b def func()等价于a(b(func)),所以动态处理时要倒序遍历装饰器列表。
  • 特殊装饰器单独处理:像property、classmethod这类特殊装饰器,需要先处理核心逻辑(比如先建property对象,再添加setter),再应用自定义装饰器。
  • 继承支持:如果需要动态类继承父类,把type的第二个参数改成父类元组即可,比如(BaseModel,)。

内容的提问来源于stack exchange,提问作者Martin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 06:13:12