Python字典遍历陷阱:值传递与引用传递的区别
本文深入解析Python字典遍历时的底层机制。当遍历基本数据类型时,变量获取的是值的拷贝,直接修改不影响原字典;而遍历列表或自定义类对象时,变量获取的是引用,修改对象内部状态会反映在原字典中。理解这一差异对于避免数据意外变更至关重要。
Python字典遍历的基本机制
在Python中,开发者通常习惯通过key和value的组合形式来遍历items。需要特别注意,如果value存储的是基本数据类型(如int、float等),遍历过程中获取的实际上是值的副本。这意味着直接对遍历变量进行修改,无法改变原字典中该键对应的值。
dict2 = {'A':4, 'B':4}
for _, num in dict2.items():
num += 1
print(dict2) # {'A': 4, 'B': 4}
若希望在这种情况下更新value,必须采用my_dict[key] = ...的方式显式赋值,例如通过键名重新指定新值。
for key, num in dict2.items():
dict2[key] += 1
print(dict2) # {'A': 5, 'B': 5}
对象引用的修改影响
然而,当value指向一个列表或自定义类的实例时,遍历获取的是该对象的引用(Reference)。此时,通过遍历变量对对象内部状态进行修改,会直接影响到原字典中存储的对象。
具体表现如下所示:
dict1 = {'A':[1,2,3,4],'B':[3,4,5,6]}
for _, indices in dict1.items():
indices.append(9)
print(dict1) # {'A': [1, 2, 3, 4, 9], 'B': [3, 4, 5, 6, 9]}
再参考以下代码示例:
```python
class MyClass:
def __init__(self, value):
self.value = value
my_dict = dict([(i, MyClass(i)) for i in range(3)])
for _, my_obj in my_dict.items():
print(my_obj.value)
print('\n')
for _, my_obj in my_dict.items():
my_obj.value += 1
for _, my_obj in my_dict.items():
print(my_obj.value)
最终的打印输出结果为:
0 1 2
1 2 3
值传递与引用传递的本质区别
综上所述,在python中通过key和value遍历字典时,value的行为机制类似于函数参数传递:对于基本数据类型执行的是值拷贝(Copy),而对于复杂对象执行的是引用传递(Reference)。
实际应用:利用引用修改列表
利用对象引用传递的特性,我们可以方便地对作为字典的列表进行操作,例如使用numpy.random.shuffle()函数来打乱列表顺序:
import random
dict1 = {'A':[1,2,3,4],'B':[3,4,5,6]}
for _, indices in dict1.items():
random.shuffle(indices)
print(dict1) # {'A': [4, 1, 3, 2], 'B': [4, 5, 6, 3]}
这一现象源自我对论文[1]开源代码[2]的研究。在论文的实现中,使用如下代码将每个cluster对应的样本索引列表进行随机打乱:
for _, cluster in clusters.items():
rng.shuffle(cluster)
此外,该论文还利用类似逻辑将全局模型的各分量拷贝至各个客户端模型,代码如下:
for learner_id, learner in enumerate(client.learners_ensemble):
copy_model(learner.model, self.global_learners_ensemble[learner_id].model)
本文关于Python字典遍历陷阱的解析到此结束。如需了解更多Python字典相关技巧,建议查阅本站历史文章或继续浏览后续内容,感谢支持。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













