zoukankan      html  css  js  c++  java
  • Python for 循环中使用append()添加可变元素,前面的值被覆盖,循环中内存应用地址不变

    在使用list.append(a), 添加动态改变的a(a = random.random())时,发现循环中每一个新的循环改变的a会在list中把之前的值全部改变;

    查找后自了,Python是基于对象引用的,append添加的是一个“地址、引用”,当这个地址内的内容改变时,前面的同“地址”的内容都改变。

    查看“内存、应用”’使用      id(object).

    简单的就不啰嗦了网上关于地址内存都有介绍,经过测试后发现,一般情况下给变量  一个新值时这个id就会改变,当然这个值若是和以前

    相同这个id就一样。在for循环中这个情况就不一样

    import random
    def test():
        return random.random()
    
    def test1():
        for i in range(3):
            for i in range(2):
                a = test()
                print('a_id=',id(a))

    结果是

    a_id= 2566513744848
    a_id= 2566513744872
    
    a_id= 2566513744848
    a_id= 2566513744872
    
    a_id= 2566513744848
    a_id= 2566513744872

    可以看到内存分配时,对应内层2次循环的给了2个2个地址,节省开支;  如果是这样的话使用list.append()最后就只有6个元素2个结果,

    但是

    import random
    
    list_a = []
    list = [1,2,3,4,5,6]
    
    
    def test():
        return random.random()
    
    def test1():
        for i in range(3):
            for i in range(2):
                a = test()
                print('a_id=',id(a))
                list_a.append(a)
        print(list_a)
    
    test1()

    结果

    a_id= 2566513744824
    a_id= 2566513744848
    a_id= 2566513744968
    a_id= 2566513744992
    a_id= 2566513745016
    a_id= 2566513745040
    
    [0.5481244502902065, 0.7452961787111314, 0.6038274060224955, 0.8269310521431017, 0.4091898711994284, 0.45233748625853376]

    可以看到地址都改变了,Python在运行时又分配的新的地址、引用,所以前面的数值没有变化。

    说了怎么多还没有到问题的重点;

    import random
    
    list_a = []
    list = [[1,1,0,1,0], [1,0,1,1,1]]
    
    def mutation(array):
        array.append(random.randint(1,10))
        return array
    
    def test2():
        for num in list:
            for i in range(3):
                a = mutation(num)
                print(a)
                print('a_id=',id(a))
                list_a.append(a)
        print(list_a)
    
    test2()
    [1, 1, 0, 1, 0, 8]
    a_id= 2566513576904
    [1, 1, 0, 1, 0, 8, 10]
    a_id= 2566513576904
    [1, 1, 0, 1, 0, 8, 10, 3]
    a_id= 2566513576904
    [1, 0, 1, 1, 1, 3]
    a_id= 2566515364744
    [1, 0, 1, 1, 1, 3, 5]
    a_id= 2566515364744
    [1, 0, 1, 1, 1, 3, 5, 4]
    a_id= 2566515364744
    
    [[1, 1, 0, 1, 0, 8, 10, 3],
     [1, 1, 0, 1, 0, 8, 10, 3],
     [1, 1, 0, 1, 0, 8, 10, 3],
     [1, 0, 1, 1, 1, 3, 5, 4],
     [1, 0, 1, 1, 1, 3, 5, 4], 
    [1, 0, 1, 1, 1, 3, 5, 4]]

    结果可以看到我向list中添加了一个新的值,但在list中元素的改变并不会改变list的id,内层3个循环中list的id始终不变,

    在加到list_a中的内层的3个循环中,始终是一个id,外层第一个循环结束后,取了此id的最后一个值,所以最后list_a的前3个值都相同。

    实际上网上一个list里加字典例子和这个道理是一样的,双层循环的内存循环了不改变id的对象,

    只是我写的时候把list变成其他形式了如([sum(list),,,]),找原因时也就看了id和转换的结果发现好多结果都一样,

    被其他的好多猜错试的好多,找了好久才发现原因。

    解决这个问题的办法是用copy,在

    mutation(array) 中copy要return的array产生一个新的id,(array = copy.copy(array)),
    至于是用浅拷贝还是深拷贝就要看array的维度。
  • 相关阅读:
    洛谷 1339 最短路
    洛谷 1330 封锁阳光大学 图论 二分图染色
    洛谷 1262 间谍网络 Tarjan 图论
    洛谷 1373 dp 小a和uim之大逃离 良心题解
    洛谷 1972 莫队
    洛谷 2158 数论 打表 欧拉函数
    洛谷 1414 数论 分解因数 水题
    蒟蒻的省选复习(不如说是noip普及组复习)————连载中
    关于筛法
    关于整数划分的几类问题
  • 原文地址:https://www.cnblogs.com/liuda9495/p/7657114.html
Copyright © 2011-2022 走看看