Python中的资源获取是初始化

时间:2019-05-09 00:21:26

标签: python raii

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

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

https://en.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")

Windows资源已发布,对吧?

2 个答案:

答案 0 :(得分:8)

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

在像Python这样的垃圾收集语言中,您的对象可以theoretically never be destroyed, even if you call del on it

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

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

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

# ... back to code that doesn't touch f ...

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

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

finally:
    f.close()

# ... back to code that doesn't touch f ...

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

无论如何,with语句采用一个 context manager ,它是定义__enter____exit__方法的类的实例(请参见{{ 3}})。

出于完整性考虑,在某些情况下您可能需要上下文管理器,但又不想为此定义整个类。在这种情况下,contextlib docs

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

class Resource:

    def method(self):
        pass

get_resource = Resource
release_resource = lambda x: None

类似于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()

您将使用如下资源:

raii_thingy.resource.method()

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

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

...并像这样使用:

with ContextManagedResource() as res:
    res.method()

with块结束后,资源将自动释放,无论获得资源的对象是否已被垃圾回收

答案 1 :(得分:0)

您自己对Wikipedia的引用说:

  

Perl,Python(在CPython实现中)和PHP管理   通过引用计数的对象寿命,从而可以使用   RAII。不再引用的对象将立即销毁   或完成并释放,因此析构函数或终结器可以释放   当时的资源。但是,在这种情况下,它并不总是惯用的   语言,并且特别不建议使用Python(建议使用   弱引用包中的上下文管理器和终结器。