如何正确复制含类对象数组的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
相关产品推荐
相关产品推荐

