python 可变对象与不可变对象对变量赋值与引用的影响

前言

为什么我要用字典类型做测试的载体
因为在实际开发的过程中,字典是使用频率非常高的一种数据结构,而且不同场景要构造不一样的字典,偶尔踩坑,还是要总结一下经验的,长长记性。

测试1:列表类型

# test1
tt_list = [0 for i in range(3)]
dd = dict()
dd.setdefault('a', tt_list)
dd['a'][0] += 1
dd.setdefault('b', tt_list)
dd['b'][1] += 1
dd.setdefault('c', tt_list)
dd['c'][2] += 1
dd

期望输出:

{'a': [1, 0, 0], 'b': [0, 1, 0], 'c': [0, 0, 1]}

实际输出:

{'a': [1, 1, 1], 'b': [1, 1, 1], 'c': [1, 1, 1]}

tt_list 为列表推导式赋值的列表,这里测试了在同一个字典对象里的初始化赋值问题,赋值目标为列表类型。
查看字典里元素值对应的内存地址:

id(dd['a']), id(dd['b']), id(dd['c'])
输出:(140408677234432, 140408677234432, 140408677234432)

明显地,上面用变量去初始化赋值并不是理想的。问题出在用tt_list初始化赋值的时候,实际字典变量指向的是tt_list变量的引用,连续赋值了3次,其实都指向了同一个内存地址,所以任何对字典变量的操作都会影响全局。
正确示例

# tt_list = [0 for i in range(3)]
dd = dict()
dd.setdefault('a', [0 for i in range(3)])
dd['a'][0] += 1
dd.setdefault('b', [0 for i in range(3)])
dd['b'][1] += 1
dd.setdefault('c', [0 for i in range(3)])
dd['c'][2] += 1
dd

输出:

{'aa': [1, 0, 0], 'bb': [0, 1, 0], 'cc': [0, 0, 1]}

查看字典元素值的内存地址:

id(dd['a']), id(dd['b']), id(dd['c'])
输出:(140408929043456, 140408929188160, 140408929171072)

测试2:字符串

tt_str = ''
dd = dict()
dd.setdefault('a', tt_str)
dd['a'] = 'a'
dd.setdefault('b', tt_str)
dd['b'] = 'b'
dd.setdefault('c', tt_str)
dd['c'] = 'c'
dd

输出:

{'a': 'a', 'b': 'b', 'c': 'c'}

第二个:

# tt_str = ''
dd = dict()
dd.setdefault('a', '')
dd['a'] = 'aa'
dd.setdefault('b', '')
dd['b'] = 'bb'
dd.setdefault('c', '')
dd['c'] = 'cc'
dd
输出: {'a': 'aa', 'b': 'bb', 'c': 'cc'}

查看下内存地址:

id(dd['a']), id(dd['b']), id(dd['c'])
输出:(140408404501936, 140408395757296, 140408394948144)

总结

实验做到这一步,结论有了,虽然问题看起来是变量赋值和引用的区别,但其实涉及到的知识点是python中的可变对象与不可变对象。

不可变对象 :int,str,float,tuple – 可理解为C中,值传递
可变对象 :list,dict – 可理解为C中,指针传递

还不明白的话,可以继续拿其它数据类型做测试。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值