用Python进行资源获取的初始化

Chr*_*isz 5 python raii

我是Python的新手。我来自C ++。

在一些代码审查中,我有几个同龄人希望我将事情从initdel转移到start和stop方法。在大多数情况下,这与数十年来使用C ++的RAII背道而驰。

https://zh.wikipedia.org/wiki/Resource_acquisition_is_initialization

RAII在Python中不是问题吗?不是吗

毕竟,我们可以抛出异常,并且我们想在这样做时释放资源,不是吗?

如果不是这样。有人可以提供一些有关为什么事情做得不同的见解吗?有我不懂的语言功能吗?

如果我有:

class Poop:
    def __init__:
        # Get some Windows Resource
    def __del__:
        #Release some Windows Resource

def foo():
    poop = Poop()
    raise Exception("Poop happens")
Run Code Online (Sandbox Code Playgroud)

Windows资源已发布,对吗?

gmd*_*mds 8

RAII在C ++中起作用,因为破坏是确定性的。

在像Python垃圾回收的语言,你的对象可能理论上从来没有被破坏,即使你打电话del就可以了

无论如何,在Python中处理资源的惯用方式不是使用RAII,也不使用start/ stop,而是使用上下文管理器

最简单的示例是使用文件对象:

with open('this_file.txt') as f:
    #  ... do stuff with f ...

# ... back to code that doesn't touch f ...
Run Code Online (Sandbox Code Playgroud)

with语句或多或少是一个try-finally块,它创建资源并确保在块结束时清除资源;像这样的东西:

try:
    f = open('this_file.txt')
    #  ... do stuff with f ...

finally:
    f.close()

# ... back to code that doesn't touch f ...
Run Code Online (Sandbox Code Playgroud)

我不懂Java,但是我相信JVM也使用垃圾回收,并且类似地,它try-finally是Java中资源管理的惯用法。

无论如何,该with语句采用一个上下文管理器,它是定义__enter____exit__方法的类的实例(请参阅docs)。

为了完整起见,在某些情况下您可能需要上下文管理器,但又不想为此定义整个类。在这种情况下,contextlib 可能会有所帮助

一个可行的例子;说您有资源:

class Resource:

    def method(self):
        pass

get_resource = Resource
release_resource = lambda x: None
Run Code Online (Sandbox Code Playgroud)

类似于RAII的类可能如下所示:

class RAIILike:

    def __init__(self):
        self.resource = get_resource()

    def __del__(self):
        release_resource(self.resource)

    def do_complex_thing(self):
        #  do something complex with resource
        pass

raii_thingy = RAIILike()
Run Code Online (Sandbox Code Playgroud)

您将使用如下资源:

raii_thingy.resource.method()
Run Code Online (Sandbox Code Playgroud)

另一方面,上下文管理的资源可能看起来像这样……

class ContextManagedResource:

    def __enter__(self):
        self._resource = get_resource()
        return self._resource

    def __exit__(self, exc_type, exc_value, traceback):
        if exc_type is not None:
            #  handle exception here
            pass

        else:
            pass

        release_resource(self._resource)
        return True
Run Code Online (Sandbox Code Playgroud)

...并像这样使用:

with ContextManagedResource() as res:
    res.method()
Run Code Online (Sandbox Code Playgroud)

一旦with块结束时,该资源将被自动释放,而不管所获得它的对象是否已经被垃圾收集