遇到了python关于del的小问题,又引发了一些问题,就简单的记录下,如果有不同意见,欢迎一起讨论~
python类似java是有垃圾回收机制的语言,所以我们不需要像c++一样通过析构函数来手动释放内存,
但是python也同样提供了__del__释放方法。当一个对象的引用计数为0时,会被自动调用,那么先来说说
引用计数吧。
1.引用计数
#!/usr/bin/env python
#coding:UTF-8
import sys
class MyClass(object):
def __init__(self):
print('i am __init__ function')
def __del__(self):
print('i am __del__ function')
if __name__ == '__main__':
m1 = MyClass()
m2 = m1
print(sys.getrefcount(m1))
结果如下图:
结果很让人吃惊吧,只有两个实例,为什么引用计数是3 ?
都知道python是一门脚本语言,解释型语言,但是不知道大家有没有注意python其实也是有编译过程的。
.pyc文件就是个很好的证明。可以去/usr/lib/python看看
所以说的细致一点python是一门先编译后解释的语言,编译指的是编译成为字节码,然后然逐行解释字节码。
平时解释器帮我们做好了而已,你可能会说上面的代码怎么看不见.pyc文件呢,你把函数单独成一个.py文件
然后import导入后编译就可以看见了。其实.pyc文件只是编译后的 PyCodeObject存储在硬盘上的表现而已。
编译产生的真正的结果是PyCodeObject
过程.py ->编译 -> PyCodeObject ->解释(虚拟机执行)
现在说引用计数,绕了个弯,其实也不算,因为引用计数的值不对就是因为python的编译过程。
详情可参考http://blog.csdn.net/balabalamerobert/article/details/1649490
2.__del__
前面说了python的引用计数为0时会自动回收对象,所以一般是不推荐我们使用python中的__del__删除方法的
我在自己使用__del__过程中就遇到了一个问题,还是看代码:
定义了两个类,一个基类MyClass有名字和电话等信息,派生类DerClass添加了地址,每个类都有一个attribute属性
glb和der_glb。
#!/usr/bin/env python
#coding:UTF-8
class MyClass(object):
glb = 100 #global variable
def __init__(self, nm, ph):
self.name = nm
self.phone = ph
class DerClass(MyClass):
der_glb = 200 #global variable
def __init__(self, nm, ph, addr):
super.__init__(nm, ph) #python3
self.address = addr
def __del__(self):
#del self.__class__.der_glb
del self.der_glb
print 'del der_glb'
if __name__ == '__main__':
m1 = MyClass('wwh', '123')
m2 = DerClass('wwh', '456', 'xian')
主要看下del函数,我在del函数中自己调用了del self.der_glb来删除这个所有类共用的变量
(python中类内定义的变量所有实例共用)
结果报错了
但是我改为del self.__class__.der_glb却正确了
这是什么原因呢
前面说了python中类内定义的变量所有实例共用,那么每个实例在结束后也就是自己的引用计数为0时都会被调用del
也就是说每个实例都del了一遍只有一份的der_glb变量,当然是不对的
那么为什么加上__class__就正确了呢
python的内存模型应该是我们定义了一个类后,这个类的模板module也会在内存中存储一份(id(Der_class)可证明),毕竟它还有所有实例需要用的变量等等。
所以__class__含义应该是获取到内存中这个module的地址,然后取得module的der_glb,删除它。
删除它后我们当然不能使用它了。
类似python的delattr(obj, attr)删除类的属性一样
在我按照上面所说的进行修改后,del self.__class__.der_glb,运行成功,并且再次定义类的实例时访问der_glb属性报错,报错结果如下:
可见在del der_glb后,再次使用der_glb显示has no attibute 'der_glb',证明前面我所说的是正确的,该属性已经被删除
说明一下python中的der_glb类似c++中的static变量,所有实例被共用,但是在python中被称为该类的属性attribute。
虽然python很好用,但是也需要搞清楚一些原理 ^_^