__del__方法在不期望的情况下在python中被调用 [英] __del__ method being called in python when it is not expected

查看:185
本文介绍了__del__方法在不期望的情况下在python中被调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是python的新手,并且一直在研究Swaroop CH的 Python字节中的示例。我看到 __ del __ 方法的某些行为令我感到困惑。



基本上,如果我运行以下脚本(在Python 2.6.2中)

  class Person4:
'''代表一个人'''
人口= 0

def __init __(自己,名字):
'''初始化人员的数据'''
self.name =名称
print'初始化%s'%self.name

#创建人员时,他们会增加人口
Person4.population + = 1

def __del __(self):
'我在死''
打印'%s说再见'%self.name

Person4.population-= 1

如果Person4.population == 0:
print'我是最后一个'
else:
print'还有%d剩余'%Person4.population


swaroop = Person4('Swaroop')
kaleem = Person4('Kalem')

使用Python控制台(或Spyder交互式控制台),我看到以下内容:



< blockquote>



execfile(u'C:\1_eric\Python\test1.py')

初始化Swaroop

初始化Kalem



execfile(u'C:\1_eric\Python\test1.py')

初始化Swaroop

Swaroop说再见

我是最后一个

初始化Kalem

Kalem说再见

我是最后一个




为什么<$在第二次运行 __ init __ 之后立即调用c $ c> __ del __ 方法吗?

我猜想,自从使用相同的实例名称( waroop和 kaleem)来释放原始实例并对其进行垃圾回收。但是,这似乎对当前的人口数量造成了破坏。



这是怎么回事?

避免这种混乱的好方法是什么?

避免使用的 __ del __
在重用现有实例名称之前检查它们吗?
...



谢谢,
Eric

解决方案

一般建议:不要在Python中使用__ del __。它可以通过多种方式破坏垃圾回收,特别是。在对象之间进行循环引用的情况下。



在您的示例中,存在各种与execfile()的使用相关的问题-这不是最佳做法-并且重新定义全局变量。顺便说一句,如果您确实需要创建一个伪析构函数(即,每当对象被垃圾回收时都会调用的代码),请编写一个所谓的 finalizer函数(它不是析构函数),然后使用weakref对其进行调用.ref回调。当然,它不应该是实例方法,并且请记住lambda实际上创建了一个闭包,因此请确保不要在回调中泄漏任何对self的引用!如果您需要销毁实例中的数据,请使用func默认参数方法,只需确保从不在lambda中引用 self,否则将无法正常工作。

 从weakref导入ref 
从时间导入睡眠

class Person4:
'''代表一个人'''
人口= 0

def __init __(self,name):
'''初始化该人的数据'''
self.name = name
print'Initializing%s'%self.name

#创建人后,他们会增加人口
Person4.population + = 1

self ._wr = ref(self,lambda wr,name = self.name:Person4_finalizer(name))

def Person4_finalizer(name):
'''我在垂死'''
打印'%s说再见'%名称

Person4.population-= 1

如果Person4.population == 0:
print'我是最后一个'
其他:
打印'还有%d剩余'%Person4.population

p1 = Person4(一个)
p2 = Person4(两个)
p3 = Person4(三)

del p2
del p3
sleep(5)

输出(有睡眠可以帮助您查看发生的事情):

 初始化一个
两个
初始化三个
两个说再见
还有两个剩下的
三个说再见
还有一个剩下的
一个说再见
我是最后一个


I am new to python and have been working through the examples in Swaroop CH's "A Byte of Python". I am seeing some behavior with the __del__ method that is puzzling me.

Basically, if I run the following script (in 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')

using the Python console (or the Spyder interactive console) I see the following:

execfile(u'C:\1_eric\Python\test1.py')
Initializing Swaroop
Initializing Kalem

execfile(u'C:\1_eric\Python\test1.py')
Initializing Swaroop
Swaroop says bye
I am the last one
Initializing Kalem
Kalem says bye
I am the last one

Why is the __del__ method being called immediately after the __init__ on the second run?
I am guessing that since the same instance names ('swaroop' and 'kaleem') are being used that it is releasing the original instance and garbage collecting it. But, this seems to be playing havoc with the current population count.

What is going on here?
What is a good way to avoid this sort of confusion?
Avoid the use of __del__? Check for existing instance names before reusing them? ...

Thanks, Eric

解决方案

General advice: don't use __ del __ in Python. It can break garbage collection in a number of ways, esp. in the case of circular references between objects.

In your example, there're various issues related to the usage of execfile() - which is not a best practice - and the redefinition of global variables. By the way, if you really need to create a pseudo-destructor (i.e. a code that is invoked whenever the object gets garbage collected), write a so-called "finalizer" function (it's not properly a destructor) and invoke it using weakref.ref callback. It should NOT be an instance method of course, and remember that lambda actually creates a closure, hence be sure not to leak any reference to self in the callback! If you need data from the destroyed instance, use the func default argument approach, just be sure never to reference 'self' inside the lambda, otherwise it won't work.

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)

output (the sleep is there to help see what's happening):

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

这篇关于__del__方法在不期望的情况下在python中被调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆