ELe*_*Lee 6 python object-lifetime del
我是python的新手,并且一直在研究Swaroop CH的"A Byte of Python"中的示例.我看到一些__del__令我困惑的方法的行为.
基本上,如果我运行以下脚本(在Python 2.6.2中)
class Person4:
'''Represents a person'''
population = 0
def __init__(self, name):
'''Initialize the person's data'''
self.name = name
print 'Initializing %s'% self.name
#When the person is created they increase the population
Person4.population += 1
def __del__(self):
'''I am dying'''
print '%s says bye' % self.name
Person4.population -= 1
if Person4.population == 0:
print 'I am the last one'
else:
print 'There are still %d left' % Person4.population
swaroop = Person4('Swaroop')
kaleem = Person4('Kalem')
Run Code Online (Sandbox Code Playgroud)
使用Python控制台(或Spyder交互式控制台),我看到以下内容:
execfile(u'C:\ 1_eric\Python\test1.py')
初始化Swaroop
初始化Kalemexecfile(u'C:\ 1_eric\Python\test1.py')
初始化Swaroop
Swaroop说再见
我是最后一个
初始化Kalem
Kalem说再见
我是最后一个
为什么在第二次运行__del__后立即调用该方法__init__?
我猜测,因为正在使用相同的实例名称('swaroop'和'kaleem')它正在释放原始实例并且垃圾收集它.但是,这似乎对目前的人口数量造成了严重破坏.
这里发生了什么?
什么是避免这种混淆的好方法?
避免使用__del__?在重用之前检查现有实例名称?...
谢谢,埃里克
Gre*_*ill 19
这里有几件事情.当你的Person4类实例化时,其初始化population类变量0.从您的交互式控制台,你似乎是运行你的"test1.py"文件多次.第二次运行它时,Person4会再次声明该类,这使得它在技术上与第一个不同(即使它具有相同的名称).这意味着它有自己的独立population计数.
现在,swaroop和kaleem是全局变量,无论是你的"test1.py"的实例之间共享.Python内部使用引用计数来进行大多数自动垃圾收集,因此第一个Person4类的原始实例在第二次赋值之前不会被释放swaroop.分配swaroop减少第一个实例的引用计数,导致__del__被调用,因为引用计数现在为零.但是因为你在Person4里面用名字引用__del__(),当前一个实例消失时,它会减少新的 Person4.population计数,而不是旧的Person4人口数.
希望这是有道理的.我可以看到为什么这可能让学习Python的人感到困惑.您在重新定义Person4类使用的同时使用类变量execfile()进一步使问题更加混乱.为了它的价值,我编写了很多Python代码,我认为我不需要使用__del__特殊方法.
一般建议:不要在Python中使用__ del __.它可以通过多种方式破坏垃圾收集,尤其是 在对象之间循环引用的情况下.
在您的示例中,存在与execfile()的使用相关的各种问题 - 这不是最佳实践 - 以及全局变量的重新定义.顺便说一句,如果你真的需要创建一个伪析构函数(即每当对象被垃圾收集时调用的代码),写一个所谓的"终结器"函数(它不是一个正确的析构函数)并使用weakref调用它.ref回调.它当然不应该是一个实例方法,并且记住lambda实际上创建了一个闭包,因此请确保不要在回调中泄漏对self的任何引用!如果你需要来自被破坏实例的数据,请使用func默认参数方法,确保永远不要在lambda中引用'self',否则它将无效.
from weakref import ref
from time import sleep
class Person4:
'''Represents a person'''
population = 0
def __init__(self, name):
'''Initialize the person's data'''
self.name = name
print 'Initializing %s'% self.name
#When the person is created they increase the population
Person4.population += 1
self._wr = ref(self, lambda wr, name=self.name: Person4_finalizer(name))
def Person4_finalizer(name):
'''I am dying'''
print '%s says bye' % name
Person4.population -= 1
if Person4.population == 0:
print 'I am the last one'
else:
print 'There are still %d left' % Person4.population
p1 = Person4("one")
p2 = Person4("two")
p3 = Person4("three")
del p2
del p3
sleep(5)
Run Code Online (Sandbox Code Playgroud)
输出(睡眠是为了帮助看看发生了什么):
Initializing one
Initializing two
Initializing three
two says bye
There are still 2 left
three says bye
There are still 1 left
one says bye
I am the last one
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2139 次 |
| 最近记录: |