代码之家  ›  专栏  ›  技术社区  ›  nerdfever.com

为什么del<object>不删除它?

  •  3
  • nerdfever.com  · 技术社区  · 6 年前

    下面的代码创建一个“tee”对象,该对象将stdout与文件以及终端连接起来。

    如果做 del t 如下所示,当我完成测试时,对象不会被删除,并且 __del__() 成员未被调用(因此tee ing继续):

    t = tee("foo.txt")
    print("bar")
    del t
    

    但如果我打电话 α-Delphi() 直接说来,一切正常:

    t = tee("foo.txt")
    print("bar")
    t.__del__()
    

    为什么 del 工作?正确的方法是什么?

    class tee():
        def __init__(self, filepath):
            self.old_stdout = sys.stdout
            self.old_stderr = sys.stderr
            self.name = filepath
    
            sys.stdout = self
            sys.stderr = self
    
        def write(self, text):
            self.old_stdout.write(text)
            with open(self.name, 'a',  encoding="utf-8") as f:
               f.write(text)
    
        def flush(self):
            pass
    
        def __del__(self):
            sys.stdout = self.old_stdout
            sys.stdout = self.old_stderr
    
    2 回复  |  直到 6 年前
        1
  •  7
  •   asynts    6 年前

    注释 del x 不直接调用 x.__del__() 前者将x的引用计数递减一,后者仅在x的引用计数达到零时调用。
    取自 data model Python3文档的一节。

    您在构造函数中引用了类:

    sys.stdout = self
    sys.stderr = self
    

    引用将保留,因此对象将保留 活着的 .

        2
  •  2
  •   Matthias    6 年前

    你实际上要找的是 with-statement 用于特定上下文的。你打开文件,做点什么,然后再关闭它。

    with tree(“foo.txt) as t:
        t.write(“bar”)
    

    这将在最后调用exit方法。

    class tee():
        def __init__(self, filepath):
            self.old_stdout = sys.stdout
            self.old_stderr = sys.stderr
            self.name = filepath
    
            sys.stdout = self
            sys.stderr = self
    
        def write(self, text):
            self.old_stdout.write(text)
            with open(self.name, 'a',  encoding="utf-8") as f:
               f.write(text)
    
        def flush(self):
            pass
    
        def __exit__(self):
            sys.stdout = self.old_stdout
            sys.stdout = self.old_stderr
    

    实际上,您的类对write方法中的文件处理程序执行相同的操作。

    对于delete方法: 正如前面提到的,delete语句只会减少引用计数器。一旦引用的数量达到零,对象将被垃圾收集,并调用delete方法。但这不会发生在您的情况下,因为对象仍然被标准输出引用。