Python中的对象引用、可变性和垃圾回收

导语:本文章记录了本人在学习Python基础之面向对象篇的重点知识及我的心得,打算入门Python的朋友们能够来一块儿学习并交流。

本文重点:python

一、明确变量保存的是引用这一本质;
二、熟悉对象引用的基础知识;
三、掌握深复制和浅复制;
四、熟悉函数传参引用时潜在的麻烦并避免。

1、对象引用基础知识

  1. 变量:是标注而不是容器。对引用式变量而言,是把变量分配给对象,反过来理解则不合理。
  2. 别名:同一个对象的不一样标注就是别名,别名指向同一对象。
  3. 标识:能够把标识理解为对象在内存中的地址。每一个变量都有标识、类型和值。对象一旦建立,它的标识毫不会变。is运算符比较两个对象的标识;id()函数返回对象标识的整数表示,即对象的内存地址。
  4. 相等性:用==运算符比较两个对象的值是否相等。注意a==b是语法糖,等同于a.__eq__(b)。
  5. ==和is的选择:咱们关注值的频率比标识要高。

当比较变量和单例值的时候应该用is。例如:X is None 或 X is not None。算法

is运算符比==要快,由于is不能重载。数据结构

2、可变性

一、元组的相对不可变性:

指tuple数据结构的物理内容(即保存的引用)不可变。也就是说元组中不可变的是元素的标识,但元组的值会随着引用的可变对象变化而变化。
tuple,list,dict,set保存的是对象的引用,而str,byte,array.array保存的是对象的值(字符,字节,数字)。函数

二、浅复制与深复制

浅复制:当复制tuple,list,dict,set时,副本之间共享内部对象的引用。copy.copy()
深复制:当复制tuple,list,dict,set时,副本之间不共享内部对象的引用。copy.deepcopy()学习

eg:浅复制小例子code

list1=[1,(55,66),[7,8,9]]
list2=list(list1)#构建副本默认为浅复制
list2[1]+=(77,88)#对元组进行+=运算会解绑list2[1],并与右端运算后的值之间从新绑定起来。
list2[2]+=[10]#对列表进行iadd运算会就地修改列表,不会发生从新绑定。
list2[0]*=3
list1[2].pop(0)
print(list1)
print(list2)
#输出:
[1, (55, 66), [8, 9, 10]]
[3, (55, 66, 77, 88), [8, 9, 10]]

分析:list2是list1的副本,咱们对list2的三个元素均做了改动,但只有列表元素的改动影响到了list1。缘由在于list1和list2的第三个列表元素共享引用,所以影响也会同步;元组由于发生了解绑的运算因此影响未同步到list1;至于数值的影响不一样步的缘由是由于浅复制针对str,byte,array.array这些对象直接将值从新保存到副本中来,不存在共享引用的内部逻辑。对象

深复制注意事项内存

  • 深复制处在循环引用的对象时,深复制算法会进入无限循环中。
  • 一些对象可能会引用不应复制的外部资源或单例值,这些对象的深复制的结果可能太深。

三、函数的参数做为引用时:

Python惟一支持的参数传递模式是共享传参。共享传参指函数的各个形式参数得到实参中各个引用的副本,即函数内部的形参是实参的别名。资源

  • 函数可能会修改做为参数传入的可变对象。
    (1)这个行为没法避免,除非在本地建立副本,或者使用不可变对象。

    (2)所以在类中直接把参数赋值给实例变量以前必定要三思,由于这样会为参数对象建立别名,修改传入参数指向的可变对象。字符串

eg:函数修改做为参数传入的全局变量

def f(a, b):
    a += b
    return a
a = [1, 2]
b = [3, 4]
f(a, b)
print(a, b)#输出[1, 2, 3, 4], [3, 4],此时列表a已经发生变化。
t = (10, 20)
u = (30, 40)
f(t, u)
print(t, u)#输出((10, 20), (30, 40)),此时元组t没有发生变化。
  • 使用可变类型做为函数参数的默认值有危险。
    缘由在于包含此类函数的类的实例在未指定初始值时会使用同一个可变默认值。当一个实例就地修改参数时会影响其余实例对默认值的调用。

3、垃圾回收

一、垃圾回收的断定规则:

  • 主要采用引用计数算法。
    在Python中每一个对象的引用都会有统计。当引用计数归零时,对象就会当即销毁。
  • 除了循环引用外没有其余引用,处在循环引用的对象都会被销毁。

二、弱引用

  • 某些状况下可能须要保存对象的引用,但不留存对象自己,此时能够借助弱引用实现。弱引用不会妨碍对象被当作垃圾回收。
  • 弱引用是一种低层机制,是weakref模块中WeakValueDictionary、WeakKeyDictionary和WeakSet等有用的集合类,以及finalize函数的底层支持。
  • 弱引用的局限性
    弱引用所指对象能够是set,用户自定义的类,list和dict的子类。不能够是int、tuple的实例及子类,也不能够是list实例或dict实例。

4、Python对不可变类型施加的把戏

一、使用一个元组来构造另外一个元组,获得的实际上是同一个元组。

二、比较字符串或整数是否相等时,应该使用==而不是is。这是因为Python解释器内部驻留的特性所致使的。

相关文章
相关标签/搜索