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

Python子类run()方法属性赋值不一致的优化方案咨询

优化子类中description字段的获取实现

我在子类中实现了run()方法,每个子类的该方法都包含API POST请求,从请求结果中提取ID并赋值给self._id。现在需要获取description字段,但SubClassB的self._api_obj.trigger(...)接口会返回description,而SubClassA的self._api_obj.trigger_run(...)接口不返回该字段,SubClassA需要单独调用API获取description。

当前实现中,SubClassB的run()方法同时赋值_id和_description,而SubClassA的run()仅赋值_id,这种同名方法行为不一致的做法不够优雅,希望找到更优的self._description赋值或获取方案。

原代码如下:

class SuperClass:
    def __init__(self):
        self._id = None  # Assigned in run()
        self._description = None

    @property
    def description(self):
        raise NotImplementedError

    def run(self, *args):
        raise NotImplementedError

    @property
    def id(self):
        return self._id


class SubClassA(SuperClass):
    def __init__(self):
        super().__init__()
        self._api_obj = ApiObj1()

    @property
    def description(self):
        if not self._description:
            _result = self._api_obj.get_data()
            self._description = _result["description"]
        return self._description

    def run(self, *args):
        _result = self._api_obj.trigger_run(foo="foo")
        self._id = _result["RunId"]


class SubClassB(SuperClass):
    def __init__(self):
        super().__init__()
        self._api_obj = ApiObj2()

    @property
    def description(self):
        return self._description

    def run(self, *args):
        _result = self._api_obj.trigger(foo="foo", bar="bar", arg1="arg1", arg2="arg2")
        self._id = _result["data"]["id"]
        self._description = _result["data"]["description"]

方案一:统一run方法职责,description全量懒加载

让run()方法只专注于触发操作并设置_id,_description的获取统一交给description属性懒加载处理,这样两个子类的run()行为完全一致,同时避免不必要的API请求(比如不需要description时就不会触发额外调用)。

修改后的代码:

class SuperClass:
    def __init__(self):
        self._id = None  # Assigned in run()
        self._description = None

    @property
    def description(self):
        raise NotImplementedError

    def run(self, *args):
        raise NotImplementedError

    @property
    def id(self):
        return self._id


class SubClassA(SuperClass):
    def __init__(self):
        super().__init__()
        self._api_obj = ApiObj1()

    @property
    def description(self):
        if not self._description:
            _result = self._api_obj.get_data()
            self._description = _result["description"]
        return self._description

    def run(self, *args):
        _result = self._api_obj.trigger_run(foo="foo")
        self._id = _result["RunId"]


class SubClassB(SuperClass):
    def __init__(self):
        super().__init__()
        self._api_obj = ApiObj2()
        self._trigger_result = None  # 存储trigger的结果,用于后续提取description

    @property
    def description(self):
        if not self._description:
            # 如果trigger已经执行过,直接从存储的结果中取
            if self._trigger_result:
                self._description = self._trigger_result["data"]["description"]
            else:
                # 极端情况:未调用run就获取description,可根据需求抛出异常或触发run
                raise RuntimeError("Please call run() first to get description")
        return self._description

    def run(self, *args):
        self._trigger_result = self._api_obj.trigger(foo="foo", bar="bar", arg1="arg1", arg2="arg2")
        self._id = self._trigger_result["data"]["id"]

方案二:抽象description获取逻辑,父类定义模板方法

在父类中定义获取description的模板方法,子类各自实现具体的获取逻辑,同时保持run()方法的一致性。

修改后的代码:

class SuperClass:
    def __init__(self):
        self._id = None  # Assigned in run()
        self._description = None

    @property
    def description(self):
        if not self._description:
            self._description = self._fetch_description()
        return self._description

    def _fetch_description(self):
        raise NotImplementedError

    def run(self, *args):
        raise NotImplementedError

    @property
    def id(self):
        return self._id


class SubClassA(SuperClass):
    def __init__(self):
        super().__init__()
        self._api_obj = ApiObj1()

    def _fetch_description(self):
        _result = self._api_obj.get_data()
        return _result["description"]

    def run(self, *args):
        _result = self._api_obj.trigger_run(foo="foo")
        self._id = _result["RunId"]


class SubClassB(SuperClass):
    def __init__(self):
        super().__init__()
        self._api_obj = ApiObj2()
        self._trigger_result = None

    def _fetch_description(self):
        if not self._trigger_result:
            raise RuntimeError("Please call run() first to get description")
        return self._trigger_result["data"]["description"]

    def run(self, *args):
        self._trigger_result = self._api_obj.trigger(foo="foo", bar="bar", arg1="arg1", arg2="arg2")
        self._id = self._trigger_result["data"]["id"]

方案三:强制run()完成所有必要数据加载

如果业务上要求run()执行后必须获取到所有后续需要的字段,可以让SubClassA在run()中主动调用获取description的API,这样两个子类的run()都完成_id和_description的赋值,行为完全一致。但要注意这种方式会增加API请求次数,如果不需要description时会造成浪费。

修改后的代码:

class SuperClass:
    def __init__(self):
        self._id = None  # Assigned in run()
        self._description = None

    @property
    def description(self):
        return self._description

    def run(self, *args):
        raise NotImplementedError

    @property
    def id(self):
        return self._id


class SubClassA(SuperClass):
    def __init__(self):
        super().__init__()
        self._api_obj = ApiObj1()

    def run(self, *args):
        _result = self._api_obj.trigger_run(foo="foo")
        self._id = _result["RunId"]
        # 主动调用API获取description
        desc_result = self._api_obj.get_data()
        self._description = desc_result["description"]


class SubClassB(SuperClass):
    def __init__(self):
        super().__init__()
        self._api_obj = ApiObj2()

    def run(self, *args):
        _result = self._api_obj.trigger(foo="foo", bar="bar", arg1="arg1", arg2="arg2")
        self._id = _result["data"]["id"]
        self._description = _result["data"]["description"]

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 04:50:35