How to force deletion of a python object?

前端 未结 4 1214
逝去的感伤
逝去的感伤 2020-11-30 19:36

I am curious about the details of __del__ in python, when and why it should be used and what it shouldn\'t be used for. I\'ve learned the hard way that it is n

4条回答
  •  醉话见心
    2020-11-30 19:52

    The way to close resources are context managers, aka the with statement:

    class Foo(object):
    
      def __init__(self):
        self.bar = None
    
      def __enter__(self):
        if self.bar != 'open':
          print 'opening the bar'
          self.bar = 'open'
        return self # this is bound to the `as` part
    
      def close(self):
        if self.bar != 'closed':
          print 'closing the bar'
          self.bar = 'close'
    
      def __exit__(self, *err):
        self.close()
    
    if __name__ == '__main__':
      with Foo() as foo:
        print foo, foo.bar
    

    output:

    opening the bar
    <__main__.Foo object at 0x17079d0> open
    closing the bar
    

    2) Python's objects get deleted when their reference count is 0. In your example the del foo removes the last reference so __del__ is called instantly. The GC has no part in this.

    class Foo(object):
    
        def __del__(self):
            print "deling", self
    
    if __name__ == '__main__':
        import gc
        gc.disable() # no gc
        f = Foo()
        print "before"
        del f # f gets deleted right away
        print "after"
    

    output:

    before
    deling <__main__.Foo object at 0xc49690>
    after
    

    The gc has nothing to do with deleting your and most other objects. It's there to clean up when simple reference counting does not work, because of self-references or circular references:

    class Foo(object):
        def __init__(self, other=None):
            # make a circular reference
            self.link = other
            if other is not None:
                other.link = self
    
        def __del__(self):
            print "deling", self
    
    if __name__ == '__main__':
        import gc
        gc.disable()   
        f = Foo(Foo())
        print "before"
        del f # nothing gets deleted here
        print "after"
        gc.collect()
        print gc.garbage # The GC knows the two Foos are garbage, but won't delete
                         # them because they have a __del__ method
        print "after gc"
        # break up the cycle and delete the reference from gc.garbage
        del gc.garbage[0].link, gc.garbage[:]
        print "done"
    

    output:

    before
    after
    [<__main__.Foo object at 0x22ed8d0>, <__main__.Foo object at 0x22ed950>]
    after gc
    deling <__main__.Foo object at 0x22ed950>
    deling <__main__.Foo object at 0x22ed8d0>
    done
    

    3) Lets see:

    class Foo(object):
        def __init__(self):
    
            raise Exception
    
        def __del__(self):
            print "deling", self
    
    if __name__ == '__main__':
        f = Foo()
    

    gives:

    Traceback (most recent call last):
      File "asd.py", line 10, in 
        f = Foo()
      File "asd.py", line 4, in __init__
        raise Exception
    Exception
    deling <__main__.Foo object at 0xa3a910>
    

    Objects are created with __new__ then passed to __init__ as self. After a exception in __init__, the object will typically not have a name (ie the f = part isn't run) so their ref count is 0. This means that the object is deleted normally and __del__ is called.

提交回复
热议问题