未调用python析构函数
我有一个很大的脚本,在那里我发现很多与机器的连接都是打开的,原因是其中一个类的析构函数从未被调用 下面是一个简化版本的脚本,说明了这个问题。 我四处分层搜索,发现这可能是因为GC和weakref确实有帮助,但在本例中没有帮助 我可以看到调用析构函数的两种情况是未调用python析构函数,python,destructor,Python,Destructor,我有一个很大的脚本,在那里我发现很多与机器的连接都是打开的,原因是其中一个类的析构函数从未被调用 下面是一个简化版本的脚本,说明了这个问题。 我四处分层搜索,发现这可能是因为GC和weakref确实有帮助,但在本例中没有帮助 我可以看到调用析构函数的两种情况是 如果我调用B_类对象而不传递_类函数 self.b = B_class("AA") 我称之为使B_类对象不全局,即不使用self b = B_class("AA",self.myprint) b.do_something() 这两
self.b = B_class("AA")
b = B_class("AA",self.myprint)
b.do_something()
import weakref
class A_class:
def __init__(self,debug_level=1,version=None):
self.b = B_class("AA",self.myprint)
self.b.do_something()
def myprint(self, text):
print text
class B_class:
def __init__(self,ip,printfunc=None):
self.ip=ip
self.new_ip =ip
#self.printfunc = printfunc
self.printfunc = weakref.ref(printfunc)()
def __del__(self):
print("##B_Class Destructor called##")
def do_something(self,timeout=120):
self.myprint("B_Class ip=%s!!!" % self.new_ip)
def myprint(self,text):
if self.printfunc:
print ("ExtenalFUNC:%s" %text)
else:
print ("JustPrint:%s" %text)
def _main():
a = A_class()
if __name__ == '__main__':
_main()
实际上并没有使用weakref
s来解决您的问题;这条线实际上是一个角落。使用weakref.ref(printfunc)
创建一个weakref
,但随后使用调用参数将其从weakref
转换回存储的强引用(并且weakref
对象立即消失)。显然,不可能将weakref
存储到绑定方法本身(因为绑定方法是每次在self
上引用它时创建的自己的对象,而不是一个生命周期与self
绑定的缓存对象),所以您必须稍微有点黑客行为,解除绑定方法,以便可以对对象本身执行weakref
。Python3.4的引入简化了这一点,但如果您不能使用它,那么您只能手工操作
尝试将其更改为(在Python 2.7上,您必须import-inspect
):
并将myprint
更改为:
def myprint(self,text):
if self.printfuncref is not None:
printfunc = self.printfuncref()
if printfunc is None:
self.printfuncref = self.printobjref = None # Ref died, so clear it to avoid rechecking later
elif self.printobjref is not None:
# Bound method not known to have disappeared
printobj = self.printobjref()
if printobj is not None:
print ("ExtenalFUNC:%s" %text) # To call it instead of just saying you have it, do printfunc(printobj, text)
return
self.printobjref = self.printfuncref = None # Ref died, so clear it to avoid rechecking later
else:
print ("ExtenalFUNC:%s" %text) # To call it instead of just saying you have it, do printfunc(text)
return
print ("JustPrint:%s" %text)
是的,很难看。如果你愿意的话,你可以把难看的部分去掉(借用是有道理的,但是名字必须改变;
\uuuuu self\uuuuu
在Py2中是\uu self
,\uuuu func\uuuuuuu>是im\u func
),但即使这样也很不愉快。如果weakref
s实际上会变暗,这肯定不是线程安全的,因为对weakref
成员的检查和清除没有受到保护。您没有正确使用weakref.ref
对象。创建后立即调用它,返回引用的对象(作为printref
传入的函数)
通常,您希望保存弱引用,并且仅在要使用reffered to对象时调用它(例如,在myprint
中)。但是,这对绑定方法self.myprint
不起作用,因为绑定方法对象没有任何其他引用(每次访问一个方法都会创建一个新对象)
如果您使用的是Python 3.4或更高版本,并且您知道传入的对象始终是绑定方法,那么可以使用,而不是常规的ref
。如果不确定将获得哪种类型的可调用,则可能需要执行一些类型检查,以查看是否需要WeakMethod
。使用Python的“with”语句()。
它创建一个语法作用域,它创建的函数保证在执行离开该作用域时被调用。您还可以通过从contextlib模块创建一个带有“contextmanager”装饰器的生成器来模拟“\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
以下是政治公众人物的一个例子:
import contextlib
@contextlib.contextmanger
def opening(filename):
f = open(filename) # IOError is untouched by GeneratorContext
try:
yield f
finally:
f.close() # Ditto for errors here (however unlikely)
然后在主代码中编写
with opening(blahblahblah) as f:
pass
# use f for something
# here you exited the with scope and f.close() got called
在您的情况下,您需要使用不同的名称(连接或其他名称),而不是“打开”,并在您的上下文管理器中进行套接字连接/断开连接。非常感谢您的回复!。。但是这里有一个问题…当do_something()被称为weakref时,weakref已经死了,基本上printfunc从未被使用过…有解决方法吗?是的,问题似乎是绑定方法本身在不再被引用时被收集,而不是在它绑定到的对象被收集之后。事实上,任何维持生命的简单机制都会以不同的方式创造一个循环。我能想到的最好的解决方案是在收到方法时解除该方法的绑定,将其拆分为实例和函数。我会更新,包括该选项,但它的丑陋。再次感谢!。。。你能更新我该怎么做吗(当你收到方法并将其拆分为实例和函数时,解除方法的绑定)?我就是这么做的。希望有帮助;不过,就代码可读性/复杂性而言,它显然是次优的,因此(正如我所指出的),将Python3.4+的weakref.WeakMethod
类向后移植以简化它可能是有意义的。我要指出的是,如果您可以通过切换到使用上下文管理来避免使用\u del\uuuu
,这可能是一个更好的选择(因为这意味着您可以让循环垃圾收集器处理循环)。同样,如果您可以使用Python 3.4或更高版本,那么即使涉及到\uu del\uu
,循环也不会成为问题。
import contextlib
@contextlib.contextmanger
def opening(filename):
f = open(filename) # IOError is untouched by GeneratorContext
try:
yield f
finally:
f.close() # Ditto for errors here (however unlikely)
with opening(blahblahblah) as f:
pass
# use f for something
# here you exited the with scope and f.close() got called