###2022年10月4日
本文是《Python学习备忘录》的第2部,前面7章需要看《Python学习备忘录》
8、对象引用
8.1 正确认识Python中的变量
Python中,变量不是对象的的盒子,而只是对象盒子上的标签,一个盒子可以贴多个标签。
8.1 is和’‘''的区别
is是比较两个变量指向的引用是否为同一个引用,底层是比较两个变量的引用的id()的值是否一致,
‘’’'是比较两个变量的值是否相等,底层调用__eq__方法进行比较。
8.2 元组的相对不可变性
元组与多数Python集合一样,保存的是对象的引用。如果引用对象是可变的,即使元组本身不可变,元素依然可变。也就是说,元组的不可变特性其实是指tuple数据结构的物理内容(即保存的引用)不可变,与引用的对象无关。
8.3 并非所有的变量都是对象的引用
str、bytes和array.array等单一类型序列是扁平的,它们保存的不是引用,而是在连续的内存中保存数据本身(字符、字节和数字)。
8.4、默认做浅复制
8.4.1 复制列表(或多数内置的可变集合)最简单的方式是使用内置的类型构造方法。如:
l1 = [3, [44, 55], (7, 8, 9)]
l2 = list(l1)
对列表或其他可变序列来说,还能使用简洁的l2 = l1[:]语句创建副本。
然而,构造方法或者[:]做的是浅复制(即复制了最外层容器,副本中的元素是源容器中元素的引用)。如果所有元素是不可变的,那么这样没有问题,还能节省内存。但是,如果有可变的元素,可能就会导致意想不到的问题。
copy模块的copy和deepcopy函数能为任意对象做浅复制和深复制。
8.4.2 函数的参数
1)Python函数内部的形参是实参中各个引用的副本,也就是浅复制。此时,如果传入的实参是可变的,那么在函数内部就可以修改这个实参。
2)不要将可变类型作为参数的默认值,尤其不要在类的__init__方法中将可变类型作为默认值。
因为所有的实例,用的是同一个副本(即浅复制),如果是可变类型,则不同实例都会修改这个副本。比如一个类有3个实例,这三个实例又都用了同一个列表默认值,则它们都会修改这个列表,就会容易引发意想不到的后果。
8.4.3 del语句
del语句删除名称,而不是对象。仅当删除的变量保存的是对象的最后一个引用或者无法得到对象时,del语句才会导致对象被当垃圾回收。
8.4.4垃圾回收
在CPython中,垃圾回收主要使用的算法是引用计数。实际上,每个对象都会统计有多少引用指向自己。当引用计数归零时,对象立即就被销毁:CPython会在对象上调用__del__方法(如果定义了),然后释放分配给对象的内存。
9、符合python风格的对象
9.1 classmethod与staticmethod
classmethod装饰器定义了操作类的方法,由它装饰的方法第一个参数的类本身,而不是实例。它最常见的用途是定义备选构造方法。按照约定,类方法的第一个参数名为cls(但是python并不介意具体怎么命名),并且无论有没有指明第一个参数名,classmethod装饰的方法第一个参数始终是这个类。
staticmethod装饰器装饰的函数是静态函数,其实就是一个普通函数,只是碰巧在类的定义体中而不是模块层定义,它装饰的函数第一个参数不是特殊值。