Python对象拷贝异常:修改拷贝对象导致原对象部分属性同步变更
问题根源:可变对象的浅拷贝引用共享
这问题的核心在于可变对象与不可变对象在拷贝时的行为差异,你的__copy__方法里对inputs的处理是浅拷贝(直接传递引用),而max_p这类数值是不可变类型,赋值时会创建新的独立值,所以才会出现只有inputs同步变更的情况。
具体拆解原因:
不可变类型(如
max_p的float值)
当你在__copy__里写max_p=self.max_p时,因为float是不可变类型,Python会直接复制这个值到新对象里。后续修改拷贝对象的max_p,只是给拷贝对象的这个属性重新赋值一个新的float值,完全不会影响原对象的max_p——这就是为什么你修改拷贝组件的max_p后,原对象的这个属性完全不受影响。可变类型(如
inputs的字典)
字典是可变对象,当你在__copy__里直接传递inputs=self.inputs时,你并没有创建一个新的字典,而是把原对象inputs字典的引用传给了拷贝对象。这意味着拷贝对象和原对象共享同一个字典内存地址:- 当你调用
component.add_input('a', 12)时,本质是在修改这个共享的字典内容,所以原对象的inputs也会跟着变化。 - 而如果是给拷贝对象的
inputs重新赋值一个新字典(比如component.inputs = {'a':12}),那才会切断引用,但你的add_input方法应该是在原字典里添加键值对,不是重新赋值。
- 当你调用
解决方案:对可变属性做深/浅拷贝
修改你的__copy__方法,对inputs、outputs这类可变对象创建独立的副本:
def __copy__(self, name=None, nice_name=None): if name is None: name = self.name if nice_name is None: nice_name = self.nice_name # 对字典类型的可变属性做拷贝,避免引用共享 copied_inputs = self.inputs.copy() copied_outputs = self.outputs.copy() copied_streams = self.streams.copy() # 如果streams也是可变类型的话 return ConversionComponent( name=name, nice_name=nice_name, lifetime=self.lifetime, maintenance=self.maintenance, capex=self.capex, capex_unit=self.capex_unit, scalable=self.scalable, base_investment=self.base_investment, base_capacity=self.base_capacity, economies_of_scale=self.economies_of_scale, max_capacity_economies_of_scale=self.max_capacity_economies_of_scale, ramp_down=self.ramp_down, ramp_up=self.ramp_up, shut_down_ability=self.shut_down_ability, shut_down_time=self.shut_down_time, start_up_time=self.start_up_time, number_parallel_units=self.number_parallel_units, min_p=self.min_p, max_p=self.max_p, inputs=copied_inputs, outputs=copied_outputs, main_input=self.main_input, main_output=self.main_output, streams=copied_streams, final_unit=self.final_unit )
如果你的字典里还嵌套了其他可变对象(比如字典里的值是列表或自定义对象),那需要用copy.deepcopy()来彻底创建独立副本:
import copy copied_inputs = copy.deepcopy(self.inputs)
验证你的输出结果
看你最后一次修改后的输出:
copy {'a': 12} 95.0 original {'a': 12} 1.0
完全符合这个逻辑:inputs因为共享引用被同步修改,而max_p是不可变类型,修改拷贝对象的max_p只是给它赋了新值,原对象的max_p还是保持原来的1.0。
内容的提问来源于stack exchange,提问作者ulicious
相关产品推荐
相关产品推荐

