有人可以解释为什么以下代码的行为方式如下:
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"
Run Code Online (Sandbox Code Playgroud)
输出(注意d2的析构函数从不被调用)是这个(python 2.7)
delete d1
after d1
func called
after d2
func called
delete d3
after d3
Run Code Online (Sandbox Code Playgroud)
有没有办法"修复"代码,以便调用析构函数而不删除添加的方法?我的意思是,放置d2.func = None的最佳位置是析构函数!
谢谢
[编辑]根据前几个答案,我想澄清一点,我不是在询问使用的优点(或缺乏优点)__del__.我试图创建最短的函数,以证明我认为是非直观的行为.我假设已经创建了一个循环引用,但我不确定为什么.如果可能的话,我想知道如何避免循环引用....
Nic*_*tin 35
你不能假设__del__将永远被调用 - 它不是一个希望资源自动解除分配的地方.如果要确保释放(非内存)资源,则应该创建一个release()或类似的方法,然后显式调用它(或者在上面的注释中由Thanatos指出的上下文管理器中使用它).
至少你应该仔细阅读__del__ 文档,然后你可能不应该尝试使用__del__.(另请参阅有关其他不良内容的gc.garbage 文档__del__)
Bre*_*yer 16
我提供了自己的答案,因为虽然我很欣赏要避免的建议__del__,但我的问题是如何让它能够正常运行所提供的代码示例.
简短版本:以下代码用于weakref避免循环引用.在发布问题之前,我以为我已经尝试了这个,但我想我一定做错了.
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"
Run Code Online (Sandbox Code Playgroud)
更长版本:当我发布问题时,我确实搜索了类似的问题.我知道你可以使用with,而流行的情绪__del__是不好的.
使用with有意义,但仅限于某些情况.打开一个文件,阅读它并关闭它是一个很好的例子,它with是一个非常好的解决方案.你已经去了需要对象的特定代码块,并且你想要清理对象和块的结尾.
数据库连接似乎经常被用作不能正常使用的示例with,因为您通常需要保留创建连接的代码部分并在更加事件驱动(而非顺序)的时间范围内关闭连接.
如果with不是正确的解决方案,我会看到两种选择:
虽然我试图提供简化的代码,但我的真正问题更多是事件驱动的,因此with不是一个合适的解决方案(with对简化代码来说很好).我也想避免atexit,因为我的程序可以长时间运行,并且我希望能够尽快执行清理.
因此,在这种特定情况下,我发现它是使用weakref和防止循环引用的最佳解决方案,这将阻止__del__工作.
这可能是规则的一个例外,但是有一些使用情况,weakref并且__del__是正确的实现,恕我直言.
Fal*_*rri 11
您可以使用运算符代替delwith.
http://effbot.org/zone/python-with-statement.htm
就像文件类型对象一样,你可以这样
with Dummy('d1') as d:
#stuff
#d is guaranteed to be out of scope
Run Code Online (Sandbox Code Playgroud)
del 不打电话 __del__
del在您使用的方式删除局部变量.__del__在对象被销毁时调用.Python作为一种语言并不能保证它何时会破坏一个对象.
CPython作为Python最常见的实现,使用引用计数.因此,del通常会按预期工作.但是,如果您有参考周期,它将无法工作.
d3 -> d3.func -> d3
Run Code Online (Sandbox Code Playgroud)
Python没有检测到这一点,所以不会马上清理它.而且它不仅仅是参考周期.如果抛出异常,您可能仍希望仍然调用析构函数.但是,Python通常会将局部变量作为其回溯的一部分.
解决方案不依赖于__del__方法.相反,使用上下文管理器.
class Dummy:
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
print "Destroying", self
with Dummy() as dummy:
# Do whatever you want with dummy in here
# __exit__ will be called before you get here
Run Code Online (Sandbox Code Playgroud)
这保证可以工作,您甚至可以检查参数以查看是否正在处理异常并在这种情况下执行不同的操作.
| 归档时间: |
|
| 查看次数: |
41812 次 |
| 最近记录: |