当你第一次学习python时,你可能会有很多疑问,尤其是所谓的“可变数据类型”和“不可变数据类型”。python和C/C++不同的是,它的变量使用有其自身的特点。当你第一次学习python时,你必须记住“一切都是对象,一切都是对象的引用”这句话。事实上,这个特征类似于JAVA,所以你不必担心python中的C/C++指针的复杂性。下面的文章将分析python中的“可变数据类型”和“不可变数据类型”。
首先,我们需要知道python中哪些是可变数据类型,哪些是不可变数据类型。可变数据类型:列表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) 31106508
>>>x+=2 >>>id(x) 31106484
上述程序都是操作不可变数据类型中的int类型,id()查看当前变量的地址值。我们先来看x = 1和y = 根据12个操作结果,从上面的输出可以看出,此时x和y的地址值是相同的,也就是说,x和y实际上引用了相同的对象,即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,然后x、y、Z已经引用了这个对象,所以数据类型int是不可变的。如果你想再次赋值int类型的变量,它相当于在内存中创建一个新对象,而不是以前的对象。上述程序的过程可以从下图中看到。
图1 python不可变数据类型分析
从上述过程可以看出,不可变数据类型的优点是,无论内存中有多少引用,相同的对象只占用一个内存,但其缺点是,当需要计算变量以改变变量引用对象的值时,因为它是不可变的数据类型,所以必须创建新的对象,这将一次又一次地创建新的对象,但不再使用的内存将被垃圾回收器回收。
(2)可变数据类型分析。让我们先看看下面的程序。
>>>a=[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.append(4)和a += [2]发现这两个操作使a引用的对象值成为上述最终结果,但a引用的地址仍为41575088,即a引用的地址值不会改变,而是在地址后面扩展新地址,改变存储在地址中的值,因此可变数据类型意味着在操作变量时,其值是可变的,值的变化不会导致新对象,即地址不会改变,但地址中的内容已经改变或地址已经扩展。下图显示了这个过程,您可以清楚地看到这个过程。
图2 python可变数据类型分析
从上述过程可以看出,可变数据类型允许同一对象的内容,即值可以改变,但地址不会改变。但需要注意的是,可变数据类型的操作不能直接进行新的赋值操作,如a = [1, 2, 3, 4, 5, 6, 7]这样的操作不是改变值,而是建立了一个新的对象,这里的可变只是类似于append、+=等这个操作。
简而言之,总结上述过程是:“python中不可变数据类型,不允许变量值变化,如果变量值变化,相当于新对象,对于相同值的对象,内存中只有一个对象,会有一个引用计来记录有多少变量引用对象;
可变数据类型允许变量值发生变化,即如果apend进行变量、+=这种操作后,只会改变变量值,而不是新对象,变量引用对象的地址不会改变,但对于相同值的不同对象,存储中会有不同的对象,即每个对象都有自己的地址,相当于存储多个相同值的对象,这里没有引用计数,是真实的对象。”
最后,我们主要区分什么是变量值的变化,什么是变量引用对象地址的变化这些概念非常清楚,说写一些程序测试似乎是真实的,所以建议你有任何疑问可以写一些基本的程序测试来知道结果。如果您有新的意见,请添加,谢谢。
推荐课程:Python for Beginners(微软官方视频课程)