• Python里list的复制问题


    写代码的时候发现的……太傻了……
    查了一下发现里面还有学问,尤其是对列表里嵌套列表要格外注意!

    浅拷贝

    意思是修改了原列表/复制列表里的值,另一个列表也会被改变。可以理解为它们的内存是同一块地方?只是给了一个新的指针指向那里。所以无论改哪个,另一个都会被修改。

    什么时候会出现浅拷贝?

    我可以总结为没有使用deepcopy()的全是浅拷贝吗?

    • python里列表list采用“=”赋值的时候
      当修改等号右边的原list时,新list也会改变。
    >>> x = [1,2,3,4]
    >>> y = x
    >>> y.pop()
    4
    >>> y
    [1, 2, 3]
    >>> x
    [1, 2, 3]
    
    • list采用“*”复制多个列表的时候,其实和上面相同,遇到嵌套列表的时候会出问题
    >>> A = [[None,None]]
    >>> B = A*3
    >>> B[0][0]=0
    >>> A
    [[0, None]]
    >>> B
    [[0, None], [0, None], [0, None]]
    =========== 通过id()查看内存地址
    >>> id(B[0])
    44594056L
    >>> id(B[2])
    44594056L
    ============= 看到A、B里面元素的内存是一样的!
    >>> id(B[2][0])
    31897360L
    >>> id(B[2][1])
    499518584L
    >>> id(B[1][0])
    31897360L
    >>> id(B[1][1])
    499518584L
    >>> id(A[0][1])
    499518584L
    >>> id(A[0][0])
    31897360L
    >>> id(B[0])
    44594056L
    >>> id(A[0])
    44594056L
    ==============疑问!!!!!! 这个A的地址是啥呀?为啥不是44560456L呢???
    >>> id(A)
    44595080L
    >>> id(B)
    44560456L
    
    • 采用copy()函数
      Python2.7里list没有这个内置函数,会报错,但是看到有人用,Python3应该有吧…
    >>> z = x.copy()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AttributeError: 'list' object has no attribute 'copy'
    

    在没有嵌套的时候,或者字典嵌套列表的时候,copy()是可以复制字典不会被修改的。。那看来是list自己的问题。。

    >>> a = {'x':11,'y':22}
    >>> a.copy()
    {'y': 22, 'x': 11}
    >>> b = a.copy()
    >>> b.popitem()
    ('y', 22)
    >>> a
    {'y': 22, 'x': 11}
    >>> b
    {'x': 11}
    =========================
    >>> a = {'x':[11, 22], 'y':[33,44]}
    >>> b = a.copy()
    >>> a['x']=13
    >>> b
    {'y': [33, 44], 'x': [11, 22]}
    >>> a
    {'y': [33, 44], 'x': 13}
    >>> a['y']=[33,46]
    >>> b
    {'y': [33, 44], 'x': [11, 22]}
    
    • 用for循环生成列表:
    old = [1,[1,2,3],3]
    new = []
    for i in range(len(old)):
        new.append(old[i])
    print('Before:')
    print(old)
    print(new)
    new[0] = 3
    new[1][0] = 3
    print('After:')
    print(old)
    print(new)
    

    结果:

    Before:
    [1, [1, 2, 3], 3]
    [1, [1, 2, 3], 3]
    After:
    [3, [3, 2, 3], 3]
    [3, [3, 2, 3], 3]
    
    • 使用切片
    old = [1,[1,2,3],3]
    new = old[:]
    print('Before:')
    print(old)
    print(new)
    new[0] = 3
    new[1][0] = 3
    print('After:')
    print(old)
    print(new)
    

    结果:

    Before:
    [1, [1, 2, 3], 3]
    [1, [1, 2, 3], 3]
    After:
    [3, [3, 2, 3], 3]
    [3, [3, 2, 3], 3]
    

    解决方法

    采用深复制的方法!

    深复制

    介绍

    就是在内存里新开了一片地方存复制的数据,指针指的是不同的地址。

    实现

    • 使用deepcopy()函数,需要引入copy包:
    >>> import copy
    >>> z = copy.deepcopy(x)
    >>> z.pop()
    3
    >>> z
    [1, 2]
    >>> x
    [1, 2, 3]
    
    import copy
    old = [1,[1,2,3],3]
    new = copy.deepcopy(old)
    print('Before:')
    print(old)
    print(new)
    new[0] = 3
    new[1][0] = 3
    print('After:')
    print(old)
    print(new)
    

    结果:

    Before:
    [1, [1, 2, 3], 3]
    [1, [1, 2, 3], 3]
    After:
    [1, [1, 2, 3], 3]
    [3, [3, 2, 3], 3]
    
    • 解决“*”的使用问题:使用新创建的列表为每个复制的对象赋值
    >>> A = [None]
    >>> B = [A*2 for i in range(3)]
    >>> B
    [[None, None], [None, None], [None, None]]
    >>> A
    [1]
    >>> B[0][0]=2
    >>> A
    [1]
    >>> B
    [[2, None], [None, None], [None, None]]
    

    注意*和for搭配使用!给我整的有点蒙了……对比下面3个栗子

    >>> A[0]=1
    >>> B
    [[None, None], [None, None], [None, None]]
    >>> A
    [1]
    >>> B[0][0]=1
    >>> A
    [1]
    >>> B[0][0]=2
    >>> A
    [1]
    >>> B  # 明显看到只修改了B的一个值,A的值并没有改变。
    [[2, None], [None, None], [None, None]]
    ====================== 这个就是 上面提到过的嵌套列表用for是浅复制呀!
    >>> old = [1,[1,2,3],3]
    >>> new = [old for i in range(1)]
    >>> new
    [[1, [1, 2, 3], 3]]
    >>> old
    [1, [1, 2, 3], 3]
    >>> new[0][0] = 3
    >>> new
    [[3, [1, 2, 3], 3]]
    >>> old
    [3, [1, 2, 3], 3]
    ======================== for和“*”一起就变成深复制了?
    >>> old = [1,[1,2,3],3]
    >>> new = [old for i in range(2)]
    >>> new
    [[1, [1, 2, 3], 3], [1, [1, 2, 3], 3]]
    >>> new[0][0]
    1
    >>> new[0][0]=3
    >>> old
    [3, [1, 2, 3], 3]
    >>> new = [old*1 for i in range(2)]
    >>> new
    [[3, [1, 2, 3], 3], [3, [1, 2, 3], 3]]
    >>> new[0][0]=1
    >>> new
    [[1, [1, 2, 3], 3], [3, [1, 2, 3], 3]]
    >>> old
    [3, [1, 2, 3], 3]
    

    https://www.cnblogs.com/Black-rainbow/p/9577029.html
    https://www.cnblogs.com/yinghao-liu/p/8641236.html

  • 相关阅读:
    MySQL——视图/触发器/事务/存储过程/函数/流程控制
    python连接MySQL/redis/mongoDB数据库的简单整理
    docker安装和使用
    【Python】Django2.0集成Celery4.1详解
    django-haystack全文检索详细教程
    ubuntu16.04安装FastDFS-5.08
    redis之django-redis
    uva 1152 4 Values whose Sum is 0
    2015暑假acm短训小结
    Uva 12569 Planning mobile robot on Tree (EASY Version)
  • 原文地址:https://www.cnblogs.com/sweetsmartrange/p/12890477.html
Copyright © 2020-2023  润新知