Fluent Python笔记--垃圾回收

在复制list时,默认是做了浅拷贝(shallow copy),也就是说复制了最外层垯容器,而内部元素则是原容器的引用。这么做在内部元素都是不可变类型的时候没有问题,但是在内部包含可变元素的时候会发生一些意想不到的情况:

>>> l1 = [3, [66, 55, 44], (7, 8, 9)]
>>> l2 = list(l1) 
>>> l1.append(100) 
>>> l1[1].remove(55) 
>>> print('l1:', l1)
l1: [3, [66, 44], (7, 8, 9), 100]
>>> print('l2:', l2)
l2: [3, [66, 44], (7, 8, 9)]
>>> l2[1] += [33, 22] 
>>> l2[2] += (10, 11) 
>>> print('l1:', l1)
l1: [3, [66, 44, 33, 22], (7, 8, 9), 100]
>>> print('l2:', l2)
l2: [3, [66, 44, 33, 22], (7, 8, 9, 10, 11)]

所以,当容器中包含可变元素的时候,为了避免意想不到的情况发生,推荐使用深拷贝,即copy.deepcopy
Python中的函数传参是共享传参(call by sharing),即函数形参获得实参中各个引用的副本。带来的副作用是函数内部的操作可能会影响到可变类型的实参。

>>> def f(a, b):
... a += b
... return a
...
>>> x = 1
>>> y = 2
>>> f(x, y)
3
>>> x, y 
(1, 2)
>>> a = [1, 2]
>>> b = [3, 4]
>>> f(a, b)
[1, 2, 3, 4]
>>> a, b 
([1, 2, 3, 4], [3, 4])
>>> t = (10, 20)
>>> u = (30, 40)
>>> f(t, u)
(10, 20, 30, 40)
>>> t, u 
((10, 20), (30, 40))

Python默认解释器CPython中,默认使用引用计数来做垃圾回收。每个对象维护一个变量,计算自己被引用的次数,当这个值归零之后,对象被销毁,执行__del__方法。对于有循环引用的对象,则使用分代垃圾回收算法。

按照上面的说法,引用数归零之后对象被垃圾回收。有时需要引用对象而不想让它存活超过所需时间,比如缓存。
这时候就需要引入弱引用的概念。

>>> import weakref
>>> a_set = {0, 1}
>>> wref = weakref.ref(a_set) 
>>> wref

>>> wref() 
{0, 1}
>>> a_set = {2, 3, 4} 
>>> wref() 
{0, 1}
>>> wref() is None 
False
>>> wref() is None 
True

下面演示 WeakValueDictionary的用法:

class Cheese:
    def __init__(self, kind):
        self.kind = kind
    def __repr__(self):
        return 'Cheese(%r)' % self.kind

>>> import weakref
>>> stock = weakref.WeakValueDictionary() 
>>> catalog = [Cheese('Red Leicester'), Cheese('Tilsit'),
... Cheese('Brie'), Cheese('Parmesan')]
...
>>> for cheese in catalog:
... stock[cheese.kind] = cheese 
...
>>> sorted(stock.keys())
['Brie', 'Parmesan', 'Red Leicester', 'Tilsit'] 
>>> del catalog
>>> sorted(stock.keys())
['Parmesan'] 
>>> del cheese
>>> sorted(stock.keys())
[]

你可能感兴趣的:(Fluent Python笔记--垃圾回收)