我是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资源已发布,对吧?
答案 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(建议使用 弱引用包中的上下文管理器和终结器。