python - 资源获取是初始化,在 Python 中
问题描述
我是 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 资源已发布,对吗?
解决方案
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 ...
该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
语句采用上下文管理器__enter__
,它是定义和__exit__
方法的类的实例(请参阅文档)。
为了完整起见,在某些情况下您可能需要一个上下文管理器,但又不想为此定义整个类。在那种情况下,contextlib
可能会有所帮助。
一个工作的例子;说你有一个资源:
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
块结束,资源将被自动释放,无论获取它的对象是否被垃圾回收。
推荐阅读
- python - youtube频道在python中上传视频时如何获得通知
- android - 是否可以从 Facebook 帖子启动 Android Instant 应用程序?
- laravel - 设置时更改密码
- kubernetes - AKS 升级仅允许用于次要版本序列升级?
- sql - 如何使用 BigQuery 将 date_diff 用于两个相邻的会话?
- asp.net - ASP.Net - 缺少“aspx.designer.cs”文件
- arrays - 与角度 8 中的另一个数组对象比较时,如何单独过滤不匹配的数组元素
- file - 没有直接文件 url 的文件下载如何工作
- javascript - 如何从 if 语句中返回一个值并将其存储在一个变量中?jQuery
- xamarin.android - 在 Xamarin.Android 中使用 CameraSource 连续获取图像