美文网首页
2018-03-31-我复制的变量又双叒叕自己改变了

2018-03-31-我复制的变量又双叒叕自己改变了

作者: 0xC00005 | 来源:发表于2018-04-01 11:47 被阅读0次

    前言

    还在傻傻的用等号复制变量嘛?a=b?
    惊奇,发现改变a的值b的值有时候改变了有时候却不改变qwq
    原地爆炸如下:

    >>> a=123
    >>> b=a
    >>> b
    123
    >>> a
    123
    >>> b+=100
    >>> b
    223
    >>> a
    123
    >>> c=[1,2,3]
    >>> d=c
    >>> d.append(5)
    >>> d
    [1, 2, 3, 5]
    >>> c
    [1, 2, 3, 5]
    >>> ???????突然智障
    

    一股子智障的气息铺面而来

    正文

    百度科普了一下复制相关的使用姿势,get到新动作copy库里面的copy和deepcopy【???】
    然后又一次入了内存的坑
    我以前用的等号复制【我发明的名字】不仅仅会复制对象的值本身,或者说等号复制并不是创建一个新的对象,而是让一个新对象的值指向原来你复制的对象,这样就很有意思了,因为内存地址是唯一的,如果你改变了之前内存地址的值,那么新的对象也就会改变了
    这里科普一下一个去Python内存地址的新姿势id(var),使用这个函数可以去任意变量的内存地址
    首先我们定义个int类的变量,然后复制并改变:

    >>> var = 123
    >>> copy_var = var
    >>> copy_var ==var #这里证明两个变量的值相等
    True
    >>> copy_var is var #这里证明两个变量的内存地址相等
    True
    >>> uncopy_var = 123 #重新定义一个变量,发现结果一样
    >>> uncopy_var == var
    True
    >>> uncopy_var is var
    True
    

    这里可能需要瞎扯一下变量与内存的关系【又来了】
    因为这里的三个变量都是同样的一个值【这里强调一个单独的变量而不是类似于集合之类的】,Python为了节省内存空间,所以只会开辟一个内存空间......然后把所有同样的变量都指向一个内存地址

    >>> print(id(var))
    1570861024
    >>> print(id(copy_var))
    1570861024
    >>> print(id(uncopy_var))
    1570861024
    

    但是如果我改变其中的某一个值的话

    >>> copy_var+=100
    >>> copy_var is var
    False
    >>> print(id(copy_var))
    1570864224
    >>> print(id(var))      #这里可以很明显的看到加上100内存地址也是一样的加上100
    1570861024
    

    我都有点开始怀疑是不是Python专门用这段的内存地址来存储数字来着
    【而不是像某些跑得很快的语言是随意分配的】
    吓得我重新开了一遍环境:

    Python 3.6.3 |Anaconda, Inc.| (default, Oct 15 2017, 03:27:45) [MSC v.1900 64 bit (AMD64)] on win32
    Type "help", "copyright", "credits" or "license" for more information.
    >>> var = 123
    >>> print(id(var))
    1570861024
    

    妈耶还真是一样的【开始慌张】
    那么集合呢,比如列表

    >>> lst=[1,2,3,4]
    >>> copy_lst = lst
    >>> copy_lst == lst
    True
    >>> copy_lst is lst
    True
    

    现在我改变其中某一些的值。比如我对原来的lst执行压入操作

    >>> copy_lst
    [1, 2, 3, 4]
    >>> lst.append(5)
    >>> copy_lst
    [1, 2, 3, 4, 5]
    >>> lst
    [1, 2, 3, 4, 5]
    

    这又是为什么呢【突然智障】
    一种解释的方法就是因为列表是多个元素的集合,元素的内存值是不变的,但是这里因为copy_lst的内存地址=lst,所以只要lst改变了copy_lst也会改变,

    >>> id(lst[0]) == id(copy_lst[0])#元素内存地址相同
    True
    >>> id(lst) == id(copy_lst)#列表内存地址相同
    True
    

    或者还有另外一种说法,请看下面神奇的微操:

    >>> l=[] #这里是一个空列表
    >>> c=l #这里我们使用等号把l的值和内存地址复制给c
    >>> c == l #都是空列表,所以返回TRUE
    True
    >>> c is l #等号复制内存地址相同 ,也返回TRUE
    True
    >>> d =[] #新建一个空列表d
    >>> c is d #每一个**新建**的列表的内存地址都是不一样的
    False 
    >>> c == d #但是都是空列表所以值相同
    True
    

    现在导入我们的copy模块

    copy.copy 可能是藕断丝连的复制

    附:您可能需要导入【woc这么重要的模块都不是内置模块嘛】
    我先复制了上面lst的值

    import copy
    >>> copy.copy_lst=copy.copy(lst)
    >>> id(copy.copy_lst) == id(lst)
    False
    

    妙哉,但你以为这就完事大吉了?
    如果我在列表里面存列表呢?

    >>> a=[1,2,[3,4]]  #第三个值为列表[3,4],即内部元素
    >>> d=copy.copy(a) #浅拷贝a中的[3,4]内部元素的引用,非内部元素对象的本身
    >>> id(a)==id(d)
    False
    >>> id(a[2])==id(d[2])
    True
    >>> a[2][0]=3333  #改变a中内部原属列表中的第一个值
    >>> d             #这时d中的列表元素也会被改变
    [1, 2, [3333, 4]]
    

    惊不惊喜意不意外?
    这时候就需要我们的:

    copy.deep♂copy 有点黑暗的名字

    档然了我们食用的时候请去掉男魂标志
    这个方法相比较于之前的copy可不是只是有点黑♂暗而已
    他所复制出来的所有的值都是不一样的,相当于重新开辟了一段内存空间来存储

    >>> e=copy.deepcopy(a) #e为深拷贝了a
    >>> a[2][0]=333 #改变a中内部元素列表第一个的值
    >>> e
    [1, 2, [3333, 4]] #因为时深拷贝,这时e中内部元素[]列表的值不会因为a中的值改变而改变
    

    最后

    参考资料:
    copy & deepcopy 浅复制 & 深复制

    最后的最后

    我求求你们mark一下吧www

    相关文章

      网友评论

          本文标题:2018-03-31-我复制的变量又双叒叕自己改变了

          本文链接:https://www.haomeiwen.com/subject/mcyocftx.html