2017-01-20 16 views
0

У меня есть скрипт python, содержащий класс.del self vs self .__ del __() - и каков правильный способ очистки в python?

Этот класс имеет метод __del__ для обычной очистки. Если я удалю класс во время обычного выполнения скрипта, я хочу, чтобы какая-то очистка была выполнена.

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

Я заметил, что есть разница между del self и self.__del__().

А именно, self.__del__() вызывает метод del дважды.

Не могли бы вы объяснить, почему это происходит?

Это макет сценарий, чтобы проиллюстрировать этот вопрос:

import sys 
import signal 
from optparse import OptionParser 


class TestClass(object): 
    def __init__(self, 
       del_self): 
     self.del_self = del_self 

     print "__init__ with del_self = %s" % self.del_self 

    def __del__(self): 
     print "Now performing usual cleanup." 

    def signal_handler(self, arg_1, arg_2): 
     print "Received signal. Now performing unusual cleanup." 

     # Unusual cleanup 

     print "Did unusual cleanup" 

     if self.del_self: 
      print("Doing del self") 
      del self 
     else: 
      print("Doing self.__del__()") 
      self.__del__() 

     sys.exit(0) 


if __name__ == '__main__': 
    arguments = sys.argv[1:] 
    parse = OptionParser("Test.") 
    parse.add_option(
     "-d", 
     "--delself", 
     help="Set del self.", 
     type="int", 
     default=1 
    ) 

    (options, _) = parse.parse_args() 

    print "Options: %s" % options 

    tc = TestClass(del_self=options.delself) 

    signal.signal(signal.SIGQUIT, tc.signal_handler) 

    while True: 
     pass 

Если я запускал скрипт с:

python deltest.py --delself 1 

И вопрос killall -3 python я получаю:

Received signal. Now performing unusual cleanup. 
Did unusual cleanup 
Doing del self 
Now performing usual cleanup. 

Где, как , если я снова сделаю python deltest.py --delself 0, за которым следует сигнал об ударе, я получаю:

Received signal. Now performing unusual cleanup. 
Did unusual cleanup 
Doing self.__del__() 
Now performing usual cleanup. 
Now performing usual cleanup. 

Почему метод __del__ выполняется в этом случае дважды?

Спасибо!

ответ

7

del self делает практически ничего - он удаляет только локальную переменную , которая называется self. Но поскольку это не последняя ссылка на экземпляр (как бы то ни было, этот метод также имеет ссылку, по крайней мере), объект будет продолжать существовать.

Вызов __del__ вручную также не обеспечивает ничего, кроме запуска этого метода; он ничего не удаляет.

Что делает работы удаление последней ссылки на объект: в этом случае, del tc внутри основной метод было бы удалить эту последнюю ссылку, насколько я могу видеть. Тогда объект был бы собран мусором, а затем Python звонки __del__.

Так вот почему __del__ происходит дважды: один раз, когда вы вызываете его вручную как обычную функцию, и один раз, когда объект мусор собирается, когда программа заканчивается.

+0

@ random_person_123: да, это подробно поясняется [здесь] (https://docs.python.org/2/reference/datamodel.html#object.__del__) –

+0

Итак, чтобы убедиться, что я правильно понял , поскольку __del__ вызывается, когда происходит сбор мусора, мне не нужно вызывать его в обработчике сигнала, потому что он вызывается автоматически, когда экземпляр является собранным мусором. Это верно? – mayk93

+0

@ random_person_123: Да, вы никогда не называете это самим, оно автоматически вызывается, когда объект собирает мусор. Обратите внимание, что официально Python не гарантирует, что _when ваш объект будет собирать мусор, хотя CPython обычно делает это, когда последняя ссылка исчезла. – RemcoGerlich