未调用python析构函数

未调用python析构函数,python,destructor,Python,Destructor,我有一个很大的脚本,在那里我发现很多与机器的连接都是打开的,原因是其中一个类的析构函数从未被调用 下面是一个简化版本的脚本,说明了这个问题。 我四处分层搜索,发现这可能是因为GC和weakref确实有帮助,但在本例中没有帮助 我可以看到调用析构函数的两种情况是 如果我调用B_类对象而不传递_类函数 self.b = B_class("AA") 我称之为使B_类对象不全局,即不使用self b = B_class("AA",self.myprint) b.do_something() 这两

我有一个很大的脚本,在那里我发现很多与机器的连接都是打开的,原因是其中一个类的析构函数从未被调用

下面是一个简化版本的脚本,说明了这个问题。 我四处分层搜索,发现这可能是因为GC和weakref确实有帮助,但在本例中没有帮助

我可以看到调用析构函数的两种情况是

  • 如果我调用B_类对象而不传递_类函数

    self.b = B_class("AA")
    
  • 我称之为使B_类对象不全局,即不使用self

    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