我是Python的新手。我来自C ++。
在一些代码审查中,我有几个同龄人希望我将事情从init和del转移到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资源已发布,对吗?
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块结束时,该资源将被自动释放,而不管所获得它的对象是否已经被垃圾收集。
| 归档时间: |
|
| 查看次数: |
110 次 |
| 最近记录: |