递归实例方法中嵌套self的问题排查及解决方案
递归调用中字典参数被意外修改的问题解决
问题代码
class Foo: def __init__(self, params): self.params = params # 这是一个字典 def recursive_iteration(self, buffer): if buffer : # 执行某些操作 self.params['new_field'] = "new_value" else : for i in range(2): new_params = self.params new_params['some_field'] = another_value # 随i变化的值 Foo(new_params).recursive_iteration(True)
问题分析
你发现for循环第二次迭代(i=1)时,当前self.params会带上new_field字段,误以为是不同作用域的self变量互相干扰,甚至考虑要不要重构为纯函数式实现,还问能不能按作用域指定要修改的self。
但其实问题和self的作用域无关——根源是字典的引用传递:new_params = self.params并没有创建新字典,只是让new_params指向和self.params完全相同的字典对象。不管你创建多少个Foo实例,只要用的是同一个字典引用,修改操作都会作用在同一个字典上,自然会出现后续迭代看到之前修改痕迹的情况。
解决方法
把字典赋值语句改成浅拷贝即可:
new_params = self.params.copy()
这样每次循环都会生成一个原字典的独立副本,新的Foo实例操作的是自己的字典,不会影响原实例或其他循环迭代的字典。
如果你的字典里包含嵌套的可变对象(比如字典里套字典、列表),浅拷贝无法完全隔离嵌套对象的引用,这时候需要用深拷贝:
import copy new_params = copy.deepcopy(self.params)
内容的提问来源于stack exchange,提问作者John Doe
相关产品推荐
相关产品推荐

