python不可变类型为什么不可变,python中可变类型和不可变类型的区别
刚开始学python的时候,可能会有很多疑惑,尤其是刚接触到的所谓“可变数据类型”和“不可变数据类型”。与python C/C不同,它的变量使用有自己的特点。刚学python的时候,一定记得“一切都是对象,一切都是对对象的引用”这句话。其实这个特性和JAVA差不多,不用担心python里C/C里指针之类的复杂问题。本文将分析python中的“可变数据类型”和“不可变数据类型”。
首先,我们需要知道在python中哪些数据类型是可变的,哪些是不可变的。可变数据类型:list list和dict箴言;不可变数据类型:整数int,浮点float,字符串string和tuple。
然后,我们以int和list为例,看看“可变数据类型”和“不可变数据类型”有什么区别。
(1)不可变数据类型分析。先来看一段程序:x=1
id(x)
31106520
y=1
id(y)
31106520
x=2
id(x)
31106508
y=2
id(y)
31106508
z=y
id(z)
31106508x=2
id(x)
3106484以上程序都是对不可变数据类型中的int类型的操作。id()查看当前变量的地址值。我们先来看两个运算的结果,x=1,y=1。从上面的输出可以看出,此时x和y的地址值是相同的,这意味着x和y实际上引用的是同一个对象,即1,这意味着1在内存中只占用了一个地址,无论有多少个引用指向它,都只有一个地址值,但是只有一个引用计数会记录有多少个引用指向这个地址。
当我们赋值x=2时,我们发现x的地址值发生了变化。虽然还是x的引用,但是它的地址值变了。下面的y=2,z=y使得x,y,z都指向同一个对象,也就是2,所以地址值都是一样的。当X和Y都被赋值为2时,对象1对其没有引用,那么对象1所占用的内存,也就是地址31106520,将被“垃圾回收”,也就是对象1不再存在于内存中。最后X加了2,于是创建了一个新对象4,X引用了这个新对象而不是2。
那么为什么叫不可变数据类型呢?这里的不变性可以理解为X引用的地址处的值不可改变,即地址31106520处的值在被垃圾回收前始终为1,不可改变。如果要将X赋值给2,只能将X引用的地址从31106520改为31106508,相当于x=2的赋值,这就创建了另一个对象,即2。然后,X,Y,Z都引用这个对象,所以int的数据类型是不可变的。如果要再次给int类型的变量赋值,相当于在内存中创建新的对象,而不是之前的对象。从下图可以看到上面程序的流程。
图1 python不可变数据类型分析
从上面的过程可以看出,不可变数据类型的优点是无论内存中有多少个引用,同一个对象都只占用一块内存,但它的缺点是当需要对变量进行操作来改变变量引用的对象的值时,就需要创建新的对象,因为它是不可变数据类型,这样会使一次又一次的改变产生新的对象,但未使用的内存会被垃圾收集器收集。
(2)可变数据类型分析。下面同样先看一段程序。a=nbsp
;[1,2,3]
>>>id(a)
41568816
>>>a=[1,2,3]
>>>id(a)
41575088
>>>a.append(4)
>>>id(a)
41575088
>>>a+=[2]
>>>id(a)
41575088
>>>a
[1,2,3,4,2]
从上面的程序中可以看出,进行两次a = [1, 2, 3]操作,两次a引用的地址值是不同的,也就是说其实创建了两个不同的对象,这一点明显不同于不可变数据类型,所以对于可变数据类型来说,具有同样值的对象是不同的对象,即在内存中保存了多个同样值的对象,地址值不同。
接着来看后面的操作,我们对列表进行添加操作,分别a.append(4)和a += [2],发现这两个操作使得a引用的对象值变成了上面的最终结果,但是a引用的地址依旧是41575088,也就是说对a进行的操作不会改变a引用的地址值,只是在地址后面又扩充了新的地址,改变了地址里面存放的值,所以可变数据类型的意思就是说对一个变量进行操作时,其值是可变的,值的变化并不会引起新建对象,即地址是不会变的,只是地址中的内容变化了或者地址得到了扩充。下图对这一过程进行了图示,可以很清晰地看到这一过程。
图2 python可变数据类型分析
从上述过程可以看到,可变数据类型是允许同一对象的内容,即值可以变化,但是地址是不会变化的。但是需要注意一点,对可变数据类型的操作不能是直接进行新的赋值操作,比如说a = [1, 2, 3, 4, 5, 6, 7],这样的操作就不是改变值了,而是新建了一个新的对象,这里的可变只是对于类似于append、+=等这种操作。
总之,用一句话来概括上述过程就是:“python中的不可变数据类型,不允许变量的值发生变化,如果改变了变量的值,相当于是新建了一个对象,而对于相同的值的对象,在内存中则只有一个对象,内部会有一个引用计数来记录有多少个变量引用这个对象;
可变数据类型,允许变量的值发生变化,即如果对变量进行append、+=等这种操作后,只是改变了变量的值,而不会新建一个对象,变量引用的对象的地址也不会变化,不过对于相同的值的不同对象,在内存中则会存在不同的对象,即每个对象都有自己的地址,相当于内存中对于同值的对象保存了多份,这里不存在引用计数,是实实在在的对象。”
最后,大家主要区分开什么是变量值的变化、什么是变量引用的对象地址的变化这些概念就很清楚了,千说万说都不如自己动手写一些程序测试一下看看来得实在,所以建议大家有什么疑惑可以自己写一些基本的程序测试一下便知道结果。如果大家有新的意见,欢迎补充,谢谢。
推荐课程:Python for Beginners(微软官方视频课程)
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。