8.1变量不是盒子
@ 变量是别名
8.2标识,相等性和别名
@使用is ,而不是比较id()相等
@注意,在不同的解释器中,id()返回的不一定是内存地址,但一定是唯一的标注,且在变量生命周期中不变。
8.2.1 在==和 is 之间选择
@==标记值相等,而 is 比较id()相等
@ == 调用的是__eq__()方法
8.2.2 元组的相对不可变性
@元组不变是指元组的引用不变。
8.3 默认做浅赋值
@注意列表的复制是浅复制
8.3 为对象做深复制和浅复制
@使用copy.deepcopy( ) 实现深复制,deepcopy会记住已经复制的对象,避免的循环引用导致的无限循环。
@深复制有时可能太深了,对象可能引用不该复制的外部资源或单例值。我们可以实现特殊方法__copy__() 和 __deepcopy__(),控制 copy 和 deepcopy 的行为
8.4 函数的参数作为引用时
@无
8.4.1 不要使用可变类型作为参数的默认值
@假设新建类A,使用默认空列表作为一个__init__的一个默认参数,这样会导致问题:所有的类A实例都引用的是同一个列表。而且这个BUG很难发现。
@这里的问题是:默认值在定义 函数时计算(通常在加载模块时),因此默认值变成了函数对象的属性。如果默认 值是可变对象,而且修改了它的值,那么后续的函数调用都会受到影响。
@__init__ 方法检查 passengers 参数的值是不是 None,如果是就把一个新的 空列表赋值给 self.passengers。如果 passengers 不是 None,正确的实现 会把 passengers 的副本赋值给 self.passengers。
8.4.2防御可变参数
@在类的内部维护默认参数的可变类型。
@除非这个方法确实想修改通过参数传入的对象,否则在类中直接把参数赋值 给实例变量之前一定要三思,因为这样会为参数对象创建别名。如果不确 定,那就创建副本。这样客户会少些麻烦。
8.5 del和垃圾回收
@有个 __del__ 特殊方法,但是它不会销毁实例,不应该在代码中调用。即将销 毁实例时,Python 解释器会调用 __del__ 方法,给实例最后的机会,释放外部 资源
@。自己编写的代码很少需要实现 __del__ 代码,有些 Python 新手会花时 间实现,但却吃力不讨好,因为 __del__ 很难用对
@weakref包:弱引用
8.6 弱引用
@有时需要引用对象,而不让对象存在的时间超过所需时间。这经常用在 缓存中。
@弱引用不会增加对象的引用数量。引用的目标对象称为所指对象(referent)。因此我们说, 弱引用不会妨碍所指对象被当作垃圾回收。
@弱引用在缓存应用中很有用,因为我们不想仅因为被缓存引用着而始终保存缓存对象。
@weakref.ref 类其 实是低层接口,供高级用途使用,多数程序最好使用 weakref 集合和 finalize。也就是说, 应该使用 WeakKeyDictionary、WeakValueDictionary、WeakSet 和 finalize(在内部使用弱 引用),不要自己动手创建并处理 weakref.ref 实例。
8.6.1 WeakValueDictionary简介
@WeakValueDictionary 类实现的是一种可变映射,里面的值是对象的弱引用。被引用的对象 在程序中的其他地方被当作垃圾回收后,对应的键会自动从 WeakValueDictionary 中删除。
@与 WeakValueDictionary 对应的是WeakKeyDictionary, 后 者 的 键 是 弱 引 用: (WeakKeyDictionary 实例)可以为应用中其他部分拥有的对象附加数据,这样就无 需为对象添加属性。这对覆盖属性访问权限的对象尤其有用。
@weakref 模块还提供了 WeakSet 类,按照文档的说明,这个类的作用很简单:“保存元素弱 引用的集合类。元素没有强引用时,集合会把它删除。”如果一个类需要知道所有实例, 一种好的方案是创建一个 WeakSet 类型的类属性,保存实例的引用。如果使用常规的 set, 实例永远不会被垃圾回收,因为类中有实例的强引用,而类存在的时间与 Python 进程一样 长,除非显式删除类。
@这些集合,以及一般的弱引用,能处理的对象类型有限。
8.6.2 弱引用的局限
@不是每个python对象都可以作为弱引用的目标。
@基本的list 和 dict实例不能作为所指对象,但是他们的子类可以。基本set 实例可以作为所指对象,用户定义的类型也没问题,但int和tuple实例不能作为弱引用的目标,甚至他们的子类也不行。这些局限基本上是cpython的实现细节,在其他的python解释器中情况可能完全不一样。这是解释器内部优化的结果。
8.7 python对不可变类型施加的把戏。
@使用元组构建元组,得到其实是同一个元组。
@str,bytes和frozenset实例也有这种行为,X.copy( )返回的是同一个对象的引用,而不是创建一个副本。
8.8本章小结
@使用可变类型作为函数参数的默认值有危险,因为如果就地修改了参数,默认值也就改变了,这回影响以后使用默认值的调用。
@某些情况下,可能需要保存对象的引用,而不是对象本身。这是可以使用弱引用,这是一种底层机制,是weakref模块中weakvaluedictionary,weakkeydictionary和weakset等有用的集合类。以及finalize函数的底层支持。
杂谈:
@java的==比较的引用,即使是判断字符串相等也要使用.equal()函数,而python == 比较的是值相等,is判断的是引用相等,与c# 一样
@尽管这样写:open('test.txt', 'wt', encoding='utf-8').write('1, 2, 3') 是安全的,但在其他解释器下面不一定是正确的,例如Jython使用的垃圾回收策略不是引用计数,这会导致write执行时,垃圾回收程序将open返回的句柄销毁掉了。正确的做法是使用with语句,她保证文件一定会被关闭。