Как правильно очистить объект Python?

class Package: def __init__(self): self.files = [] # ... def __del__(self): for file in self.files: os.unlink(file) 

__del__(self) выше завершается с ошибкой AttributeError. Я понимаю, что Python не гарантирует существование «глобальных переменных» (данные члена в этом контексте?) При __del__() . Если это так, и это причина исключения, как я могу убедиться, что объект деструктурирует правильно?

8 Solutions collect form web for “Как правильно очистить объект Python?”

Я бы рекомендовал использовать инструкцию Python для управления ресурсами, которые необходимо очистить. Проблема с использованием явного оператора 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__ будет автоматически вызван независимо от того, происходит ли исключение.

Вы даже можете сделать такой подход еще дальше. В приведенном выше примере кто-то все еще может создавать пакет с использованием своего конструктора без использования предложения with . Вы не хотите, чтобы это произошло. Вы можете исправить это, создав класс PackageResource, который определяет методы __enter__ и __exit__ . Затем класс пакета будет определен строго внутри метода __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 

В качестве приложения к ответу Клинта вы можете упростить PackageResource с помощью contextlib.contextmanager :

 @contextlib.contextmanager def packageResource(): class Package: ... package = Package() yield package package.cleanup() 

В качестве альтернативы, хотя, вероятно, не как Pythonic, вы можете переопределить Package.__new__ :

 class Package(object): def __new__(cls, *args, **kwargs): @contextlib.contextmanager def packageResource(): # adapt arguments if superclass takes some! package = super(Package, cls).__new__(cls) package.__init__(*args, **kwargs) yield package package.cleanup() def __init__(self, *args, **kwargs): ... 

и просто используйте with Package(...) as package .

Чтобы сократить время, назовите функцию очистки и используйте contextlib.closing , и в этом случае вы можете либо использовать немодифицированный класс Package with contextlib.closing(Package(...)) помощью with contextlib.closing(Package(...)) либо переопределить его __new__ на более простой

 class Package(object): def __new__(cls, *args, **kwargs): package = super(Package, cls).__new__(cls) package.__init__(*args, **kwargs) return contextlib.closing(package) 

И этот конструктор наследуется, поэтому вы можете просто наследовать, например

 class SubPackage(Package): def close(self): pass 

Я не думаю, что, возможно, члены могут быть удалены до __del__ . Я предполагаю, что причина вашего конкретного AttributeError находится где-то в другом месте (возможно, вы ошибочно удаляете self.file в другом месте).

Однако, как указывали другие, вам следует избегать использования __del__ . Основная причина этого заключается в том, что экземпляры с __del__ не будут собирать мусор (они будут освобождены только тогда, когда их пересчет достигнет 0). Поэтому, если ваши экземпляры задействованы в циклических ссылках, они будут жить в памяти до тех пор, пока приложение запускается. (Возможно, я ошибаюсь во всем этом, мне придется снова прочитать gc docs, но я уверен, что он работает так).

Я думаю, проблема может быть в __init__ если есть больше кода, чем показано?

__del__ будет вызываться, даже если __init__ не был выполнен правильно или __del__ исключение.

Источник

Просто заверните свой деструктор с помощью инструкции try / except, и он не будет генерировать исключение, если ваши глобальные объекты уже удалены.

редактировать

Попробуй это:

 from weakref import proxy class MyList(list): pass class Package: def __init__(self): self.__del__.im_func.files = MyList([1,2,3,4]) self.files = proxy(self.__del__.im_func.files) def __del__(self): print self.__del__.im_func.files 

Он будет заполнять список файлов в функции del, которая, как гарантируется, будет существовать во время вызова. Прокси-сервер weakref должен помешать Python или самостоятельно удалить переменную self.files (если она удалена, то это не повлияет на исходный список файлов). Если это не так, что это удаляется, хотя есть больше ссылок на переменную, вы можете удалить инкапсуляцию прокси.

Кажется, что идиоматический способ сделать это – предоставить метод close() (или аналогичный) и называть его явно.

Стандартный способ – использовать atexit.register :

 # package.py import atexit import os class Package: def __init__(self): self.files = [] atexit.register(self.cleanup) def cleanup(self): print("Running cleanup...") for file in self.files: print("Unlinking file: {}".format(file)) # os.unlink(file) 

Но вы должны иметь в виду, что это сохранит все созданные экземпляры Package до тех пор, пока Python не будет прерван.

Демо с использованием приведенного выше кода, сохраненного как package.py :

 $ python >>> from package import * >>> p = Package() >>> q = Package() >>> q.files = ['a', 'b', 'c'] >>> quit() Running cleanup... Unlinking file: a Unlinking file: b Unlinking file: c Running cleanup... 

Лучшей альтернативой является использование weakref.finalize . См. Примеры в объектах Finalizer и сравнение финализаторов с методами __del __ () .

 
Interesting Posts for Van-Lav

Получение текущей даты и текущего времени только соответственно

Как заставить Python изменять xlsx-файлы при открытии приложения Excel?

Как добавить к оси datetime оси x и метки меток x с помощью Bokeh Python?

Как обрабатывать \ 2 в пути Windows с помощью Python?

Импортировать файл из родительского каталога?

Как файлы могут быть добавлены в tarfile с помощью Python без добавления иерархии каталогов?

Pythonic способ эффективно обрабатывать переменное число возвращаемых аргументов

Получение длины трека ogg из s3 без загрузки всего файла

значения по умолчанию для списка переменных аргументов в Python

Объект main built 'builtin_function_or_method' не является итерируемым

python конвертировать datetime форматированную строку в секунды

Написание функции __init__, которая будет использоваться в модели django

ImportError: невозможно импортировать имя flib

urlsafe_b64encode всегда заканчивается на '='?:

Как внедряется string.find в CPython?

Python - лучший язык программирования в мире.