「Python」对象引用和垃圾回收

  • 别名:当对象被多个变量引用时,多出来的变量称对象的别名。
  • 每个变量都有标识、类型和值。
  • 对象一旦创建就拥有一个标识,该标识在对象的生命周期内不会改变。
  • 内置id()函数返回对象的标识,is运算符比较两个对象的标识。

一个对象可以被多个变量引用;变量的标识为对象的标识,变量的值为对象中保存的数据。

在 Cpython 中对象的标识为其的内存地址,其他的 Python 实现中可能为其他值。

  • ==isis运算符比==快,因其不能重载,Python 无需寻找并调用特殊方法。==具体比较的数据视特殊方法的实现而决定。

  • 不可变序列的不可变性都是相对的,即其元素是可变的,只是每个元素的标识不会改变。


一、对象引用

1.深复制与浅复制

复制的深浅是相对与容器内元素的引用而言。简单讲,浅复制得来的副本,其内的元素直接拷贝源容器中元素的引用,这样就造成了两个容器的元素共享引用;而深复制的来的副本,会重新创建对象作为元素。而共享引用带来的问题只会在可变对象上发生,即浅复制带来陷阱的条件:对象中含有可变对象元素。

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

for i in range(7,10):
	a[3].append(i)

b
>> (1,2,3,[4,5,6,7,8,9])

 同时需注意的是,在浅复制后对一个对象的修改,不一定会反映到另一个对象,只有对对象中可变元素的原地修改,才会反映到另一个对象

a = [1,2,3,[]]
b = list(a)

a[3].append(4)
b
>> [1,2,3,[4]]

a.append(5)
b
>> [1,2,3,[4]]

a[3] = [44,55,66]
b
>> [1,2,3,[4]]

Python 中默认的复制方式都是浅复制(切片、构造方法)。

注意区分复制与变量赋值的区别,复制为创建对象的副本。

进行深复制与浅复制

copy模块提供的deepcopycopy函数能为任意对象提供深复制与浅复制。且deepcopy()函数会记住已复制的对象,因此能够优雅地处理循环引用。

2.函数的参数作为引用

 当函数形参引用可变对象,可能带来如下问题:

Ⅰ.函数参数的传引用

 Python 唯一支持的参数传递模式是共享传参,即函数内形参是实参的别名。这种方式带来的问题是,函数内部可能会原地修改参数传入的可变对象,导致函数外原对象的改变。

Ⅱ.不要使用可变类型作为函数的默认参数

 应该避免使用可变对象作为参数的默认值。带来的问题是,参数默认值在定义函数的时候计算(通常在加载模块时),因此默认值作为函数对象的属性。此时,如果默认值的可变对象,且在函数体内修改了其值,会导致后续函数调用受影响。即,函数的多次调用会使用默认参数的同一个可变对象。

二、垃圾回收

 Python 中可以使用del语句删除删除名称(变量),但del不能删除直接对象。只有当del删除了对象的最后一个引用,才会引起对的垃圾回收。

Python 中还有个特殊方法__del__,它在对象调用实例时,由解释器自动调用,给实例最后的机会释放外部资源。自己编写的代码很少需要实现__del__


 在 CPython 中,垃圾回收的主要算法是引用计数。当引用计数归零时,对象立即被销毁。同时 CPython 的垃圾回收机制还有分代垃圾回收算法,若一组对象之间全是相互引用,使得数组中的对象不可获取,此时也会引起垃圾回收。

1.弱引用

 弱引用不会增加对象的引用数量,即不会妨碍对象的垃圾回收。弱引用通常在缓存中使用,我们需要保存对象的引用,但不希望缓存由于被引用而始终存在。

发布了51 篇原创文章 · 获赞 1 · 访问量 1313

猜你喜欢

转载自blog.csdn.net/weixin_44471152/article/details/104317037