我不了解这种python __del__的行为 [英] I don't understand this python __del__ behaviour

查看:96
本文介绍了我不了解这种python __del__的行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有人可以解释为什么以下代码的行为方式:

Can someone explain why the following code behaves the way it does:

import types

class Dummy():
    def __init__(self, name):
        self.name = name
    def __del__(self):
        print "delete",self.name

d1 = Dummy("d1")
del d1
d1 = None
print "after d1"

d2 = Dummy("d2")
def func(self):
    print "func called"
d2.func = types.MethodType(func, d2)
d2.func()
del d2
d2 = None
print "after d2"

d3 = Dummy("d3")
def func(self):
    print "func called"
d3.func = types.MethodType(func, d3)
d3.func()
d3.func = None
del d3
d3 = None
print "after d3"

输出(请注意,永远不会调用d2的析构函数)是(python 2.7)

The output (note that the destructor for d2 is never called) is this (python 2.7)

delete d1
after d1
func called
after d2
func called
delete d3
after d3

有没有一种方法可以修复"代码,以便在不删除添加的方法的情况下调用析构函数?我的意思是,放置d2.func = None的最佳位置将在析构函数中!

Is there a way to "fix" the code so the destructor is called without deleting the method added? I mean, the best place to put the d2.func = None would be in the destructor!

谢谢

[edit]根据前几个答案,我想澄清一下,我并不是在问使用__del__的优点(或不足之处).我试图创建最短的函数,以证明我认为是非直觉的行为.我假设已经创建了循环引用,但是我不确定为什么.如果可能的话,我想知道如何避免使用循环引用....

[edit] Based on the first few answers, I'd like to clarify that I'm not asking about the merits (or lack thereof) of using __del__. I tried to create the shortest function that would demonstrate what I consider to be non-intuitive behavior. I'm assuming a circular reference has been created, but I'm not sure why. If possible, I'd like to know how to avoid the circular reference....

推荐答案

我提供了自己的答案,因为尽管我对避免使用__del__的建议表示赞赏,但我的问题是如何使代码正常工作?提供了示例.

I'm providing my own answer because, while I appreciate the advice to avoid __del__, my question was how to get it to work properly for the code sample provided.

短版:以下代码使用weakref来避免循环引用.我以为在发布问题之前已经尝试过此操作,但是我想我一定做错了什么.

Short version: The following code uses weakref to avoid the circular reference. I thought I'd tried this before posting the question, but I guess I must have done something wrong.

import types, weakref

class Dummy():
    def __init__(self, name):
        self.name = name
    def __del__(self):
        print "delete",self.name

d2 = Dummy("d2")
def func(self):
    print "func called"
d2.func = types.MethodType(func, weakref.ref(d2)) #This works
#d2.func = func.__get__(weakref.ref(d2), Dummy) #This works too
d2.func()
del d2
d2 = None
print "after d2"

长版: 当我发布问题时,我确实搜索了类似的问题.我知道您可以改用with,并且普遍的看法是__del__ Bad .

Longer version: When I posted the question, I did search for similar questions. I know you can use with instead, and that the prevailing sentiment is that __del__ is BAD.

使用with是有意义的,但仅在某些情况下才可以.打开文件,读取文件并将其关闭是一个很好的示例,其中with是一个很好的解决方案.您已经找到了需要对象的特定代码块,并且想要清理对象和代码块的末尾.

Using with makes sense, but only in certain situations. Opening a file, reading it, and closing it is a good example where with is a perfectly good solution. You've gone a specific block of code where the object is needed, and you want to clean up the object and the end of the block.

数据库连接似乎经常被用作使用with效果不佳的示例,因为您通常需要离开创建连接的代码部分,并在更多事件驱动的情况下关闭连接(而不是顺序的)时间范围.

A database connection seems to be used often as an example that doesn't work well using with, since you usually need to leave the section of code that creates the connection and have the connection closed in a more event-driven (rather than sequential) timeframe.

如果with不是正确的解决方案,我会看到两种选择:

If with is not the right solution, I see two alternatives:

  1. 您确保__del__可用(请参阅此博客,以获得更好的结果 弱引用的使用说明)
  2. 您可以使用atexit模块在程序关闭时运行回调.例如,请参见本主题.
  1. You make sure __del__ works (see this blog for a better description of weakref usage)
  2. You use the atexit module to run a callback when your program closes. See this topic for example.

虽然我尝试提供简化的代码,但我的真正问题更多是由事件驱动的,因此with不是合适的解决方案(with适用于简化的代码).我还想避免使用atexit,因为我的程序可以长时间运行,并且希望能够尽快执行清理.

While I tried to provide simplified code, my real problem is more event-driven, so with is not an appropriate solution (with is fine for the simplified code). I also wanted to avoid atexit, as my program can be long-running, and I want to be able to perform the cleanup as soon as possible.

因此,在这种特定情况下,我发现它是使用weakref并防止可能导致__del__无法正常工作的循环引用的最佳解决方案.

So, in this specific case, I find it to be the best solution to use weakref and prevent circular references that would prevent __del__ from working.

这可能是规则的例外,但是在某些情况下,使用weakref__del__是正确的实现,恕我直言.

This may be an exception to the rule, but there are use-cases where using weakref and __del__ is the right implementation, IMHO.

这篇关于我不了解这种python __del__的行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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