python - 如何强制删除python对象?

标签 python constructor garbage-collection destructor reference-counting

我很好奇python中__del__的细节,什么时候应该用,为什么用,什么不应该用。我学到了一个艰难的方法,它并不像人们天真地期望从析构函数中得到的那样,因为它不是 __new__/__init__ 的对立面。

class Foo(object):

    def __init__(self):
        self.bar = None

    def open(self):
        if self.bar != 'open':
            print 'opening the bar'
            self.bar = 'open'

    def close(self):
        if self.bar != 'closed':
            print 'closing the bar'
            self.bar = 'close'

    def __del__(self):
        self.close()

if __name__ == '__main__':
    foo = Foo()
    foo.open()
    del foo
    import gc
    gc.collect()

我在文档中看到 保证 __del__() 方法会在解释器退出时仍然存在的对象调用。

  1. 如何保证解释器退出时存在的任何 Foo 实例都关闭栏?
  2. 在上面的代码片段中,栏是在 del foogc.collect()... 上关闭的,还是两者都没有?如果您想更好地控制这些细节(例如,当对象未被引用时应该关闭栏)通常的实现方法是什么?
  3. __del__ 被调用时,是否保证 __init__ 已经被调用?如果 __init__ 提出了怎么办?

最佳答案

关闭资源的方法是上下文管理器,也就是 with 语句:

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

输出:

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

2) Python 的对象在引用计数为 0 时被删除。在您的示例中,del foo 删除了最后一个引用,因此立即调用了 __del__。 GC 与此无关。

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"

输出:

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

gc 与删除您和大多数其他对象无关。当简单的引用计数由于自引用或循环引用而不起作用时,它可以清理:

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"

输出:

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) 让我们看看:

class Foo(object):
    def __init__(self):

        raise Exception

    def __del__(self):
        print "deling", self

if __name__ == '__main__':
    f = Foo()

给予:

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

对象是用 __new__ 创建的,然后作为 self 传递给 __init__。在 __init__ 中出现异常后,该对象通常没有名称(即 f = 部分未运行),因此它们的引用计数为 0。这意味着对象被正常删除并调用__del__

关于python - 如何强制删除python对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6772481/

相关文章:

arrays - 用于共享数组子范围的智能垃圾收集器?

php - PHP 需要__destruct 方法吗?

c# - 在 .NET 中处理对象?

python - Django:允许从 S3 下载各种媒体文件而无需创建模型(同时隐藏 s3 存储)

java - 我们是否需要更喜欢构造函数而不是静态工厂方法?如果是这样,什么时候?

c++ - 我真的可以用圆括号初始化数组吗?

f# - 如何从 F# 中的构造函数调用方法

python - 如何通过 urls.py 使用 DRF 引发 NotFound 异常

python - 列中值的 Pandas 数据框第一个实例

python - 如何在 python 中使用 selenium 在动态 href 链接上进行循环?