为什么Python遍历列表时未更新old_hosts反而修改了未赋值的workers变量
原因解析
这个问题本质是Python的变量引用规则和可变对象的修改特性共同导致的,核心逻辑可以拆解为以下几点:
- for循环中的循环变量只是临时绑定了迭代对象的元素,一旦你对循环变量做重新赋值,就会直接断开它和原迭代对象的关联
- 列表属于可变对象,对列表内部元素的修改属于原位修改,会直接作用到该引用指向的原始对象上
代码执行流程拆解
初始状态
你定义的两个变量都是存储了子列表的引用:
workers = [['w1', 1],['w2',2]] old_hosts = [['w1',-1],['w1',-11]]
workers[0]指向内存中存储['w1', 1]的地址,old_hosts[0]指向另一个存储['w1', -1]的地址,二者完全独立。
循环内的关键操作
- 每次迭代开始时,
old_host会暂时绑定old_hosts对应位置的子列表 - 接下来你执行了赋值操作:
这行代码会从old_host = [*(worker for worker in workers if worker[0]==old_host[0])][0]workers中筛选出匹配的子列表,也就是workers[0],并直接把old_host的绑定关系改成指向workers[0]的内存地址,此时old_host和old_hosts已经没有任何关联了 - 执行
old_host[1] = 3时,因为old_host现在指向的是workers里的子列表,修改列表元素属于原位修改,直接改动了workers的原始数据 - 整个循环过程中你从来没有对
old_hosts本身做过修改,所以它的值始终保持初始状态
如果要修改old_hosts的正确写法
如果需要更新old_hosts的值同时不影响workers,需要通过索引定位到old_hosts的对应位置,并且对匹配到的workers元素做拷贝再修改:
workers = [['w1', 1],['w2',2]] old_hosts = [['w1',-1],['w1',-11]] for i in range(len(old_hosts)): old_host_val = old_hosts[i] # 匹配到worker后做拷贝,避免修改原workers matched = [w for w in workers if w[0] == old_host_val[0]][0].copy() matched[1] = 3 # 赋值回old_hosts的对应位置 old_hosts[i] = matched print('workers: ' + str(workers)) print('old_hosts: ' + str(old_hosts))
运行后输出如下,不会修改workers同时old_hosts会正常更新:
workers: [['w1', 1], ['w2', 2]] old_hosts: [['w1', 3], ['w1', 3]]
内容的提问来源于stack exchange,提问作者Aslanpour
相关产品推荐
相关产品推荐

