Python走过的坑,可变不可变数据类型

  • Python标准数据类型
  • Python不可变数据类型(一个萝卜一个坑)
  • 可变数据类型(一块地好多萝卜)


Python标准数据类型

  1. Number(数字)
  2. String(字符串)
  3. Dictionary(字典)
  4. List(列表)
  5. Tuple(元组)
  6. Set(集合)

Python不可变数据类型(一个萝卜一个坑)

比如数字,字符串,元组。这是什么意思呢,show your code:

a = 1
print("变量a在内存当中的地址":,id(a))	
a += 1
print("变量a在内存当中的地址":,id(a))

结果为

变量a在内存当中的地址 1683713088
变量a在内存当中的地址 1683713120

可以看到,变量a在内存当中的地址发生了变化,多了32个bit,也就是4个字节,这里说句题外话,在python中int代表的是长整型,没有 python2 中的 Long。
换句话说,一个数字对应一个内存地址,数字变,地址变,一个萝卜一个坑。
还有一个要注意的地方。

a = 1
print("变量a在内存当中的地址":,id(a))	
b = 1
print("变量a在内存当中的地址":,id(b))

结果为:

变量a在内存当中的地址 1683713088
变量a在内存当中的地址 1683713088

一模一样的,这说明了什么,说明了变量a和b指向了同一块内容,其实就是同一个对象的不同引用,也就是同一个人的不同名字而已。或者还是拿萝卜来说。一个坑里,只能长一个萝卜,中国人叫萝卜,老外管它叫turnip(萝卜的英文),这下懂了吧。

可变数据类型(一块地好多萝卜)

典型的就是列表,这个可吃了不少亏。
来吧

a = [1,2,3]
print("变量a在内存当中的地址":,id(a))	
a.append(4)
print("变量a在内存当中的地址":,id(a))

结果为

变量a在内存当中的地址 2635029663240
变量a在内存当中的地址 2635029663240

可以看到,一毛一样啊。这就相当于在原来的地里又长了一个萝卜,当然也许是又长了白菜,土豆什么的内建的数据类型,或者是自定义的数据类型等等。

比如a = [1,2,3,“白菜”]

来一张图更形象一点。一个矩形的土地,长了3个萝卜。

python 不支持 问号判断 python不支持的数据类型_python 不支持 问号判断


然后又扔过去一个白菜。

python 不支持 问号判断 python不支持的数据类型_Pyhton_02


地还是那块地(内存地址并没有发生改变),但是其中元素增加了。

总结为:元素变,地址不变,同一块地可以种好多萝卜,这就是可变数据类型。

这里也有一个值得注意的问题:

come on code!

a = [1,2,[3,4]]
print('a = :',a)
b = a 
b[2] = [5,6]
print('a = ',a)

结果为:

a =  [1, 2,[3, 4]]
a =  [1, 2, [5, 6]]

这里a和b所指的是同一个东西,也就是说,a和b都是[1,2,[3,4]]这个列表的引用,也就是外号。一般我们在内存中创建了一个列表,有两种情况:

  1. 需要创建一个此列表的副本,一个一模一样的列表,只不过在内存中多开辟了一块空间来。这样做的好处是,对副本所做修改不会影响到原来的列表,因为有时候我们需要原列表与修改后的列表进行对比。需要创建一个此列表的副本,一个一模一样的列表,只不过在内存中多开辟了一块空间来。这样做的好处是,对副本所做修改不会影响到原来的列表,因为有时候我们需要原列表与修改后的列表进行对比。比如:
a = [1,2,[3,4]]
b = a.copy()
a[2][-1] = 'x'
print(a)#结果为[1, 2, [3, 'x']]
print(b)#结果为[1, 2, [3, 'x']]

咦,不对呀,我明明创建了一个原列表的副本啊,怎么对a修改,b也会跟着修改呢?这是因为浅复制,深复制的问题,如果列表只有一层,那么用浅复制足够了。但是我们做项目的时候,动不动就好几层的list,因此,必须采用深复制。下面是实例代码:

import copy
a = [1,2,[3,4]]
b = copy.deepcopy(a)
a[2][-1] = 'x'
print(a)#结果为[1, 2, [3, 'x']]
print(b)#结果为[1, 2, [3, 4]]

这样,就可以完完全全地复制一个列表了。有个博客对这种情况说的挺好的, 有句话是这么说的,因为浅复制 ,复杂子对象的保存方式是作为引用方式存储的,所以修改浅复制的值和原来的值都可以改变复杂子对象的值。
2. 只需另外再创建一个对列表对象的引用即可,这种情况不需要原列表与修改后的列表进行对比,当列表比较大,又使用不到以前版本的列表时,推荐使用这种方式,节省内存。比如

a = [1,2,3]
b = a