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__
(см. docs ).
Для полноты картины могут быть случаи, когда вам нужен менеджер контекста, но вы не хотите определять целый класс только для этого.В этом случае 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
блок заканчивается, ресурс будет автоматически освобожден, независимо от того, был ли объект, который его получил, был сборщиком мусора .