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

Python类方法设计:修改自身还是返回新实例?

Python类方法:修改实例自身还是返回新实例?

核心原则与常见实践

  • 可变对象(如list、dict):Python社区的惯用做法是同时提供两种方式:
    • 原地修改的实例方法(比如list.sort()),执行后返回None,直接改变原对象状态
    • 返回新对象的独立函数或方法(比如sorted(list)),原对象保持不变
  • 不可变对象(如str、tuple):所有修改操作都返回新对象,原实例始终不可更改
  • 自定义复杂结构(如图、序列库):
    • 如果操作属于"更新自身状态"(比如序列元素重命名),可以提供原地修改的方法
    • 如果操作是"转换为新形态"(比如图的规范顶点枚举),优先返回新实例——避免破坏原对象的状态,尤其是当原对象可能被多处引用时,原地修改容易引发难以追踪的bug

你的方案分析

带参数控制是否创建新实例

你提到的这种方案:

class Seq:
    def __init__(self, seq):
        self.seq = seq

    def rename(self, lookup, create_new_instance=False):
        new_seq = [lookup[e] for e in self.seq]
        if create_new_instance:
            return Seq(new_seq)
        else:
            self.seq = new_seq
  • 优点:用一个方法覆盖两种需求,减少代码重复
  • 缺点:方法职责不够单一,用户需要额外关注参数才能理解行为,可读性较差;默认值如果设置不当,容易让用户误操作

分拆为两个独立方法(类似list.sort()和sorted)

参考Python内置类型的设计,拆分出两个方法:

class Seq:
    def __init__(self, seq):
        self.seq = seq

    # 原地修改实例
    def rename(self, lookup):
        self.seq = [lookup[e] for e in self.seq]

    # 返回新实例
    def renamed(self, lookup):
        return Seq([lookup[e] for e in self.seq])

如果担心代码冗余,可以提取私有辅助方法来复用逻辑:

class Seq:
    def __init__(self, seq):
        self.seq = seq

    def _get_renamed_seq(self, lookup):
        return [lookup[e] for e in self.seq]

    def rename(self, lookup):
        self.seq = self._get_renamed_seq(lookup)

    def renamed(self, lookup):
        return Seq(self._get_renamed_seq(lookup))
  • 优点:职责清晰,方法名直观,符合Python用户的使用直觉
  • 缺点:需要多写几个方法,但通过辅助方法可以把冗余降到最低

建议选择

如果你的类设计为可变类型,优先采用分拆方法的模式,贴合Python社区的惯用风格,降低用户的学习成本。如果你的类偏向不可变设计,则统一返回新实例,不提供任何原地修改的方法——这种设计更安全,适合需要保证对象状态稳定的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 13:34:58