Может ли переопределение деструктора Python (__del__) вызвать утечки памяти?

#python #python-3.x #memory-leaks #garbage-collection #python-3.6

#python #python-3.x #утечки памяти #сбор мусора #python-3.6

Вопрос:

У меня есть скрипт, в котором я создаю объект в облаке с помощью API и хочу удалять его в некоторых случаях в конце скрипта.

 class ObjCreator():
   def __init__(self, keep_object: bool):
      self.keep_object = keep_object
      print("init")
   
   def create_object(self):
      print("Created object using API")

   def delete_object(self):
      print("Deleting object using API")

   def __del__(self):
      print("Deleting object using API only if keep_object is False")
      if not self.keep_object:
         self.delete_object()
 

Я видел некоторые утечки памяти в программах на Python, поэтому очевидно, что GC не является префектом (т. Е. Не подлежащими сбору объектами).

Я боюсь, что переопределение функции del приведет к утечке памяти. Возможно ли это? Если да, то есть ли у вас какие-либо предложения по другому, элегантному решению?

Комментарии:

1. Добро пожаловать в SO! Просто обратите внимание, вы не перегружаете его, вы переопределяете его, возможно, это могло бы помочь с поиском ответа в Google

2. Дополнительная подсказка: для работы всех этих методов требуется добавленный параметр self — это ссылка на вызывающий класс, который Python передает явно!

3. Привет, спасибо 🙂 Я случайно пропустил self, когда писал упрощение кода для этого вопроса. Исправлено.

Ответ №1:

Ваша интуиция верна, переопределение __del__ метода означает, что метод базового класса __del__ больше не вызывается автоматически (хотя я не думаю, что здесь вероятна утечка памяти). На самом деле в документации явно упоминается это:

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

Пример кода для этого из репозитория CPython:

     def __del__(self):
        # ... your cleanup code here ...
        super().__del__()  # call to base class
 

Комментарии:

1. Это имеет значение только в том случае, если у суперкласса действительно есть __del__ метод. В частности, object не имеет __del__ .

2. В вашем примере класс является наследником. Почему это должно работать, когда нет суперкласса?

3. Если вы попытаетесь вызвать super().__del__ , когда нет суперкласса __del__ для делегирования, вы получите AttributeError .

4. @user2357112supportsMonica вот почему я не понял ответа. Рассмотрим случай, когда вы добавляете новые атрибуты к наследнику — они не будут удалены с помощью super() .__del__()

5. @xjcl — тогда зачем вообще вызывать метод super?