纸上得来终觉浅,绝知此事要躬行。
数字、字符串、列表、元组、字典、集合是 Python 的六种标准数据类型,每一个 Python 程序都必然有这些数据类型的应用,如果会熟练使用数据类型,基本上 Python 编程已经会了一半了。
首先来看一下 Python 标准数据类型的分类:
这里就有必要了解下什么是可变数据类型,什么是不可变数据类型,这对理解使用函数是否会改变传入的参数的值非常重要,也可避免因数据类型导致的程序 bug。
不可变数据类型
**不可变数据类型是:变量所指向的内存地址处的值是不可以被改变的。**你可能不太理解上面这句话,那么接着往下看。
python 世界里,一切皆为对象(object),任何变量都是对象的引用。因此不用担心 Python 有类似于 C/C++ 中指针的复杂问题。以不可变数据类型中的整数(int)为例:
随便选取一个整数,例如 18 ,在 python 中 id(18) 来获得 18 在内存中的地址。
>>> id(18)
1409838640
>>> x=18
>>> id(x)
1409838640
>>> y=18
>>> id(y)
1409838640
>>> z=18
>>> id(z)
1409838640
>>>
如上所示,在某一次 Python 程序执行的过程中,变量 18 在内存中的地址为 1409838640,你定义 x = 18; y = 18; z = 18;无论定义多少个变量,只要它的值为 18 ,他们地址均为 1409838640,在 python 内部执行垃圾回收之前,地址 1409838640 处的值一直都是 18 ,不可被改变。
有人可能有疑问了:变量 x 是整数类型,直接给 x 赋值 19 不就改改变了 x 的值了,为什么说整数是不可变数据类型 ?
答:确实改变了 x 的值,但是请注意,Python 中一切皆为对象,任何变量都是对象的引用,因此当 x = 18 时,x 是对象 18 的引用;给 x 赋值 19 时,x 是新对象 19 的引用,x 的地址变为整数 19 的内存地址,内存地址1409838640 处的值仍是 18,请看下面的交互环境输出结果。
>>> x = 19
>>> id(x)
1409838672
>>> id(19)
1409838672
>>> id(18)
1409838640
>>> id(y)
1409838640
>>> id(z)
1409838640
可以看出执行 x = 19 后变量 x 的地址就是 19 的地址 1409838672,变量 y 和 z 仍指向整数 18 。内存中对于整数 18 只占用了一个地址,而不管有多少个引用指向了它,都只有一个地址值,只是有一个引用计数会记录指向这个地址的引用到底有几个而已。当变量 x,y,z 都指向 18 时,18 的引用计数就是 3,18 在内存中只有一份,当所有的变量都不指向 18 时,垃圾回收程序就会在适当的时机收回 18 , 收回 18 后,18 这个对象在内存中就中不存在了。
之所以说 x 是不可变数据类型,指的是 x 引用的地址处的值是不能被改变的,也就是 1409838640 地址处的值在没被垃圾回收之前一直都是 18,不能改变,如果要把 x 赋值为 19 ,那么只能将 x 引用的地址从 1409838640 变为 1409838672,相当于 x = 19 这个赋值操作又创建了一个对象,即 19 这个对象。所以说整数这个数据类型是不可变的,如果想对整数类型的变量再次赋值,在内存中相当于又创建了一个新的对象,而不再是之前的对象。其他不可变类型也是同样的道理。
注意:元组是个特例,值相同的元组的地址可能不同,因为它的本质是只读的列表。
可变数据类型
可变数据类型是:变量所指向的内存地址处的值是可以被改变的。
以可变数据类型中的列表 list 为例,如果不知道 python 的列表也没关系,本文后面会介绍。
先看一段交互式环境中的输出
>>> x=[1,2,3]
>>> id(x)
2429731524424
>>> x=[1,2,3]
>>> id(x)
2429731548808
可以看出,对变量 x 执行两次同样的赋值操作,变量 x 的地址却不是同一个,这与不可变数据类型有明显的区别,其实两次赋值操作在内存中创建了两个不同的对象,因此对于可变类型,具有同样值的对象是不同的对象,他们彼此是独立的。
接下来我们来改变列表值,看一看变量地址的变化情况 。
>>> x=[1,2,3]
>>> id(x)
2429731548808
>>> y=[1,2,3]
>>> id(y)
2429731524424
>>> z=[1,2,3]
>>> id(z)
2429731565704
>>> x.append("a")
>>> x
[1, 2, 3, 'a']
>>> y
[1, 2, 3]
>>> z
[1, 2, 3]
>>> id(x)
2429731548808
>>> id(y)
2429731524424
>>> id(z)
2429731565704
>>>del x[2]
>>>x
[1,2,'a']
>>>id(x)
2429731548808
我们首先定义了三个变量 x,y,z ,分别赋值为 [1,2,3],但他们是不同的对象,因此在内存中的地址也不一样。当对变量 x 指向的列表增加一个元素 “a” 时,变量 x 的值发生的变化,但内存中的地址还和以前一样,变量 y ,z没有做任何操作,他们的值和地址都不变,后面删除列表中的第三个元素 x[2],同样发现 x 的地址仍没有变化。
因此可变数据类型是说对一个变量所指向的内存地址处的值是可以被变的,值的变化并不会引起新建对象,即地址是不会变的。
理解了可变数据类型和不可变数据类型,相信你非常容易解释如下现象:
>>> x=y=z=1
>>> x=2
>>> x,y,z #这里,y 与 z 的值没有被改变
(2,