• 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    期望输出:

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

    实际输出:

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

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

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

    明显地,上面用变量去初始化赋值并不是理想的。问题出在用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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    输出:

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

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

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

    测试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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    输出:

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

    第二个:

    # 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'}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    查看下内存地址:

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

    总结

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

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

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

  • 相关阅读:
    应用于供暖、供水管道等场景的一种智能控制阀
    java高级用法之:JNA类型映射应该注意的问题
    js检测数据类型总结
    多线程优化导入支持事务二
    常见音视频、流媒体开源编解码库及官网(四十一)
    R语言 | 绘制带P值的差异柱状图
    神经网络图像细节分析,神经网络 图像相似度
    DockerCompose中部署Jenkins(Docker Desktop在windows上数据卷映射)
    React组件
    RocketMq2 基本理论
  • 原文地址:https://blog.csdn.net/kun_csdn/article/details/126249518