Я бы рекомендовал использовать оператор Python with
для управления ресурсами, которые необходимо очистить. Проблема с использованием явного оператора close()
состоит в том, что вам нужно беспокоиться о людях, которые вообще забывают вызывать его или забывают поместить его в блок finally
, чтобы предотвратить утечку ресурсов при возникновении исключения.
Чтобы использовать оператор with
, создайте класс со следующими методами:
def __enter__(self)
def __exit__(self, exc_type, exc_value, traceback)
В приведенном выше примере вы бы использовали
class Package:
def __init__(self):
self.files = []
def __enter__(self):
return self
# ...
def __exit__(self, exc_type, exc_value, traceback):
for file in self.files:
os.unlink(file)
Тогда, когда кто-то хотел использовать ваш класс, он делал бы следующее:
with Package() as package_obj:
# use package_obj
Переменная package_obj будет экземпляром типа Package (это значение, возвращаемое методом __enter__
). Его __exit__
метод будет вызываться автоматически, независимо от того, происходит ли исключение.
Вы могли бы даже сделать этот подход еще дальше. В приведенном выше примере кто-то еще может создать экземпляр Package, используя его конструктор, не используя предложение with
. Вы не хотите, чтобы это произошло. Это можно исправить, создав класс PackageResource, который определяет методы __enter__
и __exit__
. Затем класс Package будет определен строго внутри метода __enter__
и возвращен. Таким образом, вызывающая сторона никогда не сможет создать экземпляр класса Package без использования оператора with
:
class PackageResource:
def __enter__(self):
class Package:
...
self.package_obj = Package()
return self.package_obj
def __exit__(self, exc_type, exc_value, traceback):
self.package_obj.cleanup()
Вы бы использовали это следующим образом:
with PackageResource() as package_obj:
# use package_obj