引用
python中,在对对象赋值,参数传递,函数返回等等, 都是引用传递的. 直接copy个例子来【1】:
a = [1, 2, 3]
b = a
b.append(5)
print a, b
输出结果为:
[1, 2, 3, 5] [1, 2, 3, 5]
面的结果有助于理解引用的实际情况。 具体查看一个对象的引用数,可以使用sys.getrefcount(ojb)获取,但这个函数有点邪恶,有时似乎并不给出正确的结果,正常来说获取的值都比你想要的大,一般是大1,因为给这个函数传参数也算一个引用。但有时会大得离谱,来例子:
import sys
a = "a"
sys.getrefcount(a)
在我的机器上,输出结果尽然为14,网络遛了一圈,有人说是python内部对“a”这个对象进行了应用。好吧!就这样理解把,有高见的可以留言告我一下!
拷贝【1】
拷贝主要有两种拷贝,分别以copy模块中的两个函数copy和deepcopy为代表。其中,前者复制对象本身,但对于对象中得元素,还是会使用的原本引用,copy个例子来:
list_of_lists = [ ['a'], [1, 2], ['z', 23] ]
copy_lol = copy.copy(lists_of_lists)
copy_lol[1].append('boo')
print list_of_lists, copy_lol
输出结果为:
[['a'], [1, 2, 'boo'], ['z', 23]] [['a'], [1, 2, 'boo'], ['z', 23]]
考到第二个元素的情况了 把!用的还是引用。要想全部对对象本省进行拷贝,就得使用deepcopy了。
对象回收
Python使用了垃圾回收器来自动销毁那些不再使用的对象。当对某个对象的引用计数为0时, Python能够安全地销毁这个对象。表面上看来,在使用C或者C++时经常会碰到的内存泄露问题似乎也就解决了,但实际的情况是,请你小心!再copy个例子来【2】:
class LeakTest(object):
def __init__(self):
print 'Object with id %d born here.' % id(self)
def __del__(self):
print 'Object with id %d dead here.' % id(self)
def foo():
A = LeakTest()
B = LeakTest()
A.b = B
B.a = A
if __name__ = ="__main__":
foo()
运行结果为:
Object with id 10462448 born here.
Object with id 10462832 born here.
在构造一个类时,__init__会被自动调用;在进行对象回收时,__del__会被调用。很清楚的看到对象只是被创建了,而没有被回收,原因很简单,A和B的由于互相引用,他们的引用次数是不可能为0的,自然被回收也是不可能的了。这是,就应该考虑弱引用了。
弱引用
这是相对上面“引用”的一个概念,主要不同体现在对象回收时,上面我只提到当引用数为0,对象就会自动回收。其实还有另外一种情况,当自由只有对对象的弱引用时,对象也是会被回收。直接上代码,对上例做出一些修改:
import weakref
class LeakTest(object):
def __init__(self):
print 'Object with id %d born here.' % id(self)
def __del__(self):
print 'Object with id %d dead here.' % id(self)
def foo():
A = LeakTest()
B = LeakTest()
A.b = weakref.proxy(B)
B.a = weakref.proxy(A)
if __name__ = ="__main__":
foo()
运行结果为:
Object with id 28637456 born here.
Object with id 29402736 born here.
Object with id 28637456 dead here.
Object with id 29402736 dead here.
OK了,对象被正常回收了!最后简单解说wekref中得几个函数【3】:
1.创建弱引用:
你可以通过调用weakref模块的ref(obj[,callback])来创建一个弱引用,obj是你想弱引用的对象,callback是一个可选的函数,当因没有引用导致Python要销毁这个对象时调用。回调函数callback要求单个参数(弱引用的对象)。
一旦你有了一个对象的弱引用,你就能通过调用弱引用来获取被弱引用的对象。下面的例子创建了一个对socket对象的弱引用:
>>> from socket import *
>>> import weakref
>>> s=socket(AF_INET,SOCK_STREAM)
>>> ref=weakref.ref(s)
>>> s
>>> ref
>>> ref() #调用它来访问被引用的对象
2. 创建代理对象
代理对象是弱引用对象,它们的行为就像它们所引用的对象,这就便于你不必首先调用弱引用来访问背后的对象。通过weakref模块的proxy(obj[,callback])函数来创建代理对象。使用代理对象就如同使用对象本身一样:
>>> from socket import*
>>> import weakref
>>> s=socket(AF_INET,SOCK_STREAM)
>>> ref=weakref.proxy(s)
>>> s
>>> ref
>>> ref.close() #对象的方法同样工作 callback参数的目的和ref函数相同。在Python删除了一个引用的对象之后,使用代理将会导致一个weakref.ReferenceError错误:
>>> del s
>>> ref
Traceback (most recent call last):
File "", line 1, in ?
3. getweakrefcount(obj)和getweakrefs(obj)分别返回弱引用数和关于所给对象的引用列表
参考文献: