gpt4 book ai didi

具有修饰方法和 __del__ 定义的 Python 类不会被垃圾收集 : how do I uncouple the decorated method?

转载 作者:行者123 更新时间:2023-11-28 21:53:11 25 4
gpt4 key购买 nike

我遇到了 Python3.2 的问题。如果一个类装饰了父类的一个函数并且也有一个析构函数,那么该类的实例永远不会被垃圾回收。

下面是一些说明问题的示例代码:

def super_simple_decorator(func):
def f(*args, **kwds):
return func(*args, **kwds)
return f

class Parent():
def foo(self):
pass

class Child(Parent):
def __del__(self):
print('In Child.__del__')
def __init__(self):
self.foo = super_simple_decorator(self.foo)

x = Child()
del x

import gc
_ = gc.collect()
print(gc.garbage)

如果您愿意,您也可以在运行时在装饰器中进行猴子修补并看到相同的东西:

class Garbage():
def foo(self):
pass
def __del__(self):
print('In Garbage.__del__')

g=Garbage()
g.foo = super_simple_decorator(g.foo)
del g

在每种情况下,都有未收集的垃圾,大概是因为装饰方法中存在对 self 的绑定(bind)引用。

目前升级到 Python3.4 对我来说并不是一个真正的选择,所以我正在寻找一种方法让像这样的对象得到垃圾收集。

最佳答案

导致这个问题的不是装饰器。事实上,您在它们绑定(bind)的实例上存储了一个方法。装饰器在这里只是手段,并不是真正的原因。

方法持有对 __self__ 中实例的引用,然后您通过将方法存储在带有装饰器对象的闭包中创建循环引用,返回到 self.foo不要那样做。 Python 3.3 及之前的版本不会对具有 __del__ 方法的对象的循环引用进行垃圾回收。

解包方法并存储原始函数:

self.foo = super_simple_decorator(self.foo.__func__)

foo 将不再被绑定(bind),但是,方法仅在查找类而不是实例时才被绑定(bind)。

或者在类级别实际应用装饰器:

class Child(Parent):
def __del__(self):
print('In Child.__del__')
foo = super_simple_decorator(Parent.foo)

如果两者都不是一个选项,则使用弱引用来跟踪实例,而不是引用方法,然后根据需要重新绑定(bind):

import weakref

def super_simple_decorator(method):
instance = weakref.ref(method.__self__)
func = method.__func__
def f(*args, **kwds):
self = instance() # can return None
return func(self, *args, **kwds)
return f

关于具有修饰方法和 __del__ 定义的 Python 类不会被垃圾收集 : how do I uncouple the decorated method?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27043599/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com