(六)对象引用、可变性和垃圾回收
本节主要说明,对象与对象名称之间的区别。
一、变量不是盒子,而是标签
如图。在赋值语句中,y=A()中,先创建对象A,然后将左边的变量绑定到对象上。变量只不过是标注,因此无法阻止为对象贴上多个标签(别名)
二、标识、相等性和别名
1、对象一旦创建,标识就不会改变,标识可理解为对象在内存中的地址,is运算符比较两个对象的标识符,id返回对象标识符的整数表示。
别名
标识
2、==和is
==比较两个对象的值(对象中保存的数据),is比较对象的标识。
3、元组的相对不可变性
元组的值会随着引用的可变对象的变化而变,不可变的是元素的标识
四、浅复制
1、默认做浅复制
浅复制只复制了最外层的容器,副本中的元素是源容器中元素的引用。当元素都是不可变的,可以节省内存,当元素中有可变对象时,则容易出错。
2、为任意对象做深复制和浅复制
使用copy模块的copy和deepcopy
五、函数的参数作为引用
1、python支持的参数传递是共享传参:各个形参获得实参中各个引用的副本,函数内部的形参是实参的别名。
2、不要使用可变类型作为参数的默认值
默认值在函数定义时计算(通常在加载模块时),因此默认值成了函数对象的属性。
3、防御可变参数
在类中,直接把参数赋值给实例变量,会为参数对象创建别名;如果不想因为类内的改变,去修改参数的值,则创建副本。
六、del和垃圾回收
del删除名称,不会删除对象,但此操作可能会导致对象不可获取,导致对象被删除。
在CPython中,垃圾回收主要使用算法是引用计数。每个对象会统计有多少个引用指向自己,当引用计数归零时,对象立即被销毁。
七、弱引用
没看明白,挖坑。。。。
总结
1、变量保存的是引用,简单的赋值不能创建副本;
2、对+=,*=所做的增量赋值来说,如果左边的变量绑定的是不可变对象,则会创建新对象,反之就地修改;
3、为现有的变量赋予新值,不会修改之前绑定的变量(重新绑定):如果变量是之前对象的最后一个引用,对象会被当作垃圾回收;
4、函数的参数以别名的形式传递,因此函数可能会修改通过参数传递的可变对象。在本地创建副本、传入不可变对象可以避免;
5、使用可变类型作为默认参数有危险,如果就地修改了参数,默认值也就变了,这会影响以后默认值的调用;
6、对象的引用计数归零后,对象会被立即销毁。