在处理一个bug的时候发现程序一直报错,Exception exceptions.NameError: "global name 'TEST' is not defined"。仔细审查了下源码,发现这个TEST变量是个全局变量,已经定义了。只不过在类的析构函数__del__()中解引用了del TEST

这引出了两个问题:

  1. 一个类的对象,什么时候调用析构函数?
  2. 为什么一个对象把TEST解引用了其他对象也无法访问?

Q1

在C/C++中,需要程序员自己完成垃圾回收。而在python中,是python自己完成垃圾回收工作的。在python中每个变量都有一个引用计数器来表示这个变量被引用的次数。当这个计数器为0的时候,python就会对这个变量进行垃圾回收(也就是调用类中的析构函数__del__())。

下面有一个示例

class Test():
def __init__(self):
print "This is Init Function"
def __del__(self):
print "This is Del Function"
def test():
t = Test()
print "Boom shakalaka"
if __name__ == "__main__":
print "Before run test()"
test()
print "After run test()"
print "Before Create Object"
t1 = Test()
print "After Create Object"

我们看看执行后的结果

Before run test()
This is Init Function
Boom shakalaka
This is Del Function
After run test()
Before Create Object
This is Init Function
After Create Object
This is Del Function

在执行test()函数的时候执行完成后,Test()的对象t被回收,调用析构函数__del__打印This is Del Function

Q2

在python中,全局变量使用共享内存的方式实现的。若一个对象解引用后,其他所有对象均无法访问。

class Test():
name = "test"
def __del__(self):
del Test.name
print "This is Del Function"
if __name__ == "__main__":
t1 = Test()
t2 = Test()

执行后会报错

This is Del Function
Exception AttributeError: "'NoneType' object has no attribute 'name'" in <bound method Test.__del__ of <__main__.Test instance at 0x7f4dde73fd40>> ignored

原因是在清除t1的时候对全局变量name解引用,导致t2调用析构函数时候访问异常。