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

如何正确复制含类对象数组的Python类实例?避免副本随原实例变更

问题分析与解决方案

你遇到的问题根源在于类属性和实例属性的混淆——你以为是复制逻辑出了问题,但实际上是类的属性定义方式不对,导致所有实例共享同一个属性值。咱们一步步拆解问题:

核心问题1:类B的属性是「类属性」而非「实例属性」

你在类B里直接写val=0和p=40,这属于类属性——所有B的实例都会共享这两个值。修改任何一个B实例的val,本质上是修改了类B本身的val,所以所有B实例的val都会跟着变,哪怕你用了deepcopy也没用。

核心问题2:类A的g是「类属性」而非「实例属性」

类A里的g=[]同样是类属性,这意味着所有A的实例都会共享同一个列表(虽然你当前只创建了一个A实例,但这是不规范的写法,后续扩展代码很容易出问题)。


修复后的代码

把类属性改成实例属性,在类的__init__方法里初始化每个实例独有的属性:

import copy

class B:
    def __init__(self):
        # 每个B实例都拥有自己的val和p
        self.val = 0
        self.p = 40

class A:
    def __init__(self):
        # 每个A实例都拥有自己的列表g
        self.g = []
        self.g.append(B())
        self.g.append(B())

def main():
    a = A()
    print("a.g[0] is " + str(a.g[0].val) + " , " + str(a.g[0].p))
    print("a.g[1] is " + str(a.g[1].val) + " , " + str(a.g[1].p))
    print("Copying a to b")
    b = copy.deepcopy(a)
    print ("Now updating a[0]")
    a.g[0].val = 25
    print("a.g[0] now is " + str(a.g[0].val) + " , " + str(a.g[0].p))
    print("a.g[1] now is " + str(a.g[1].val) + " , " + str(a.g[1].p))
    print("Now printing which was copied from original a")
    print("b.g[0] is " + str(b.g[0].val) + " , " + str(b.g[0].p))
    print("b.g[1] is " + str(b.g[1].val) + " , " + str(b.g[1].p))

if __name__ == "__main__":
    main()

运行结果

修复后运行代码,你会看到修改a.g[0].val后,b.g[0].val依然保持初始的0,完全符合你的预期:

a.g[0] is 0 , 40
a.g[1] is 0 , 40
Copying a to b
Now updating a[0]
a.g[0] now is 25 , 40
a.g[1] now is 0 , 40
Now printing which was copied from original a
b.g[0] is 0 , 40
b.g[1] is 0 , 40

简单总结下:

  • 如果你希望每个类实例拥有独立的属性,一定要在__init__方法里用self.xxx来定义,而不是直接在类体中定义(那是类属性,所有实例共享)。
  • copy.deepcopy本身能实现深度复制,但前提是你的类属性定义是正确的,否则复制再多也没用。

内容的提问来源于stack exchange,提问作者robin.b

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 07:17:47