Python动态类型:变量、对象和引用解析
1、变量、对象和引用
类型属于对象,而不是变量:变量名没有类型,对象才有类型,变量实质上是指向对象所在内存空间的指针,变量只是对对象的引用。
不同赋值,因为变量没有类型,所以实质上只是修改变量a为对不同类型的变量的引用。变量总是一个指向对象的指针,而不是可改变的内存区域的标签。给一个变量赋新值,并不是替换原始的对象,而是让这个变量去引用别的对象。通俗的讲就是一个变量被赋新值,只会影响这个变量,而不会影响其共享对象的变量。
>>> a=3
>>> a
3
2、对象的垃圾收集
对象包括两个头部信息:类型标志位和引用计数器。
类型标志位指对象的类型,如int,str
引用计数器指当前引用该对象的数目,当数目为0时,对象的空间被自动回收。
>>> a='abc'
>>> a
'abc'
>>> a=3.2 -->'abc'被回收
>>> a
3.2
>>>
3、共享引用(共享对象)
两个变量同时引用3这个对象
>>> a=3
>>> b=a
>>> a
3
>>> b
3
>>>
4、共享引用和相等
== 比较两个被引用的对象是否具有相同的值
is 比较实现引用的指针是否相同,即是否引用同一对象,是否为共享引用。
如1:
>>> a=[1,2]
>>> b=a
>>> a==b
True
>>> a is b
True
>>>
如2:
>>> a=[1,2]
>>> b=[1,2]
>>> a is b
False
>>> a==b
True
>>>
5、共享引用和在原位置修改
引用了一个在原位置上发生改变的对象,共享引用也同样改变。
>>> l1=[1,2,3,4]
>>> l2=l1
>>> l1
[1, 2, 3, 4]
>>> l2
[1, 2, 3, 4]
如直接给l1赋新值,则l2不变
如 l1=24 l2仍为[1,2,3,4]
>>> l1=24
>>> l1
24
>>> l2
[1, 2, 3, 4]
>>>
如改变l2所引用对象的一个元素,这类修改会在原位置上覆盖列表对象的某部分值。则l2改变,尽管实质上并未改变l1的值,l1引用了一个在原位置上发生改变的对象,也同样改变。
>>> l1=[1,2,3,4]
>>> l2=l1
>>> l1
[1, 2, 3, 4]
>>> l2
[1, 2, 3, 4]
>>> l2[2]=888
>>> l1
[1, 2, 888, 4]
>>> l2
[1, 2, 888, 4]
>>>
6、使用Python复制而不是创建引用可以避免原位置修改问题
1)、列表分片
>>> l1=[1,2,3,4]
>>> l2=l1[:]
>>> l1
[1, 2, 3, 4]
>>> l2
[1, 2, 3, 4]
>>> l2[2]=888
>>> l1
[1, 2, 3, 4]
>>> l2
[1, 2, 888, 4]
>>>
2)、复制和深度复制
>>> l1=[1,2,3,4]
>>> import copy
>>> l2=copy.copy(l1)
>>> l1
[1, 2, 3, 4]
>>> l2
[1, 2, 3, 4]
>>> l1[1]=666
>>> l1
[1, 666, 3, 4]
>>> l2
[1, 2, 3, 4]
>>>
>>> l2=copy.deepcopy(l1)
>>> l1
[1, 666, 3, 4]
>>> l2
[1, 666, 3, 4]
>>> l1[1]=2
>>> l1
[1, 2, 3, 4]
>>> l2
[1, 666, 3, 4]
>>>