Pythonic方法在__del__中关闭类似连接的对象

时间:2014-07-07 13:17:09

标签: python

我正在开发一个类似连接的对象,它实现了一个上下文管理器。强烈建议写这样的东西:

with MyConnection() as con:
    # do stuff

当然也可以这样做:

con = MyConnection()
# do stuff
con.close()

但未能关闭连接是相当有问题的。所以关闭__del__()似乎是一个好主意:

def __del__(self):
    self.close()

这看起来很不错,但有时会导致错误:

Exception ignored in: [...]
Traceback (most recent call last):
  File "...", line xxx, in __del__()
TypeError: 'NoneType' object is not callable

有时候,当调用__del__()时,close方法已被破坏。

所以我正在寻找一种很好的方法来鼓励python在销毁时正确关闭连接。如果可能,我希望避免close()__del__()

中的代码重复

5 个答案:

答案 0 :(得分:4)

如果你真的想阻止用户不关闭连接,你只能在__enter__中初始化它,或者你可以添加一个标记,发现它尚未被上下文管理器初始化。例如,像

这样的东西
class MyConnection(object):

    safely_initialized = False

    def __enter__(self):
        # Init your connection
        self.safely_initialized = True
        return self

    def do_something(self):
        if not self.safely_initialized:
            raise Exception('You must initialize the connection with a context manager!')
        # Do something

    def __exit__(self, type, value, traceback):
        # Close your connection

这样,除非在上下文管理器中,否则不会初始化连接。

答案 1 :(得分:3)

无法保证__del__实际运行的时间。由于您使用的是with语句,请改用__exit__方法。无论语句如何完成(通常,例外情况等),__exit__语句完成后都会调用with

答案 2 :(得分:1)

您可以尝试在close中调用__del__,并忽略任何例外:

del __del__(self):
    try:
        self.close()
    except TypeError:
        pass

答案 3 :(得分:0)

确实,你不能强迫你的用户使用良好的编程技巧,如果他们拒绝这样做,你就不能对他们负责。

无法保证何时调用__del__ - 在某些Pythons中它是立即的,在其他Pythons中它可能不会在解释器关闭之前发生。因此,虽然不是一个很好的选择,但使用atexit可能是可行的 - 只需确保您注册的功能足够智能,以检查资源是否已被关闭/销毁。

答案 4 :(得分:0)

weakref.finalize() 允许您在对象被垃圾回收或程序退出时执行操作。它从 Python 3.4 开始可用。

当您创建对象时,您可以调用 <div> <div *ngFor="let post of postsList"> {{post}} </div> </div> ,为其提供一个回调来清理您的对象所拥有的资源。

Python 文档提供了 several examples of its use

finalize()

以及表示临时目录的类的 this example,其内容在以下情况下被删除:

  • 它的 >>> import weakref >>> class Object: ... pass ... >>> kenny = Object() >>> weakref.finalize(kenny, print, "You killed Kenny!") <finalize object at ...; for 'Object' at ...> >>> del kenny You killed Kenny! 方法被调用
  • 它会被垃圾收集
  • 程序退出

以先发生者为准。

remove()