Невозможно сослаться на импортированный модуль в __del __ ()

Я использую __del__() объекта, чтобы отменить подписку на событие (используя схему событий, аналогичную this):

import my_enviroment
class MyClass():
    def __del__(self):
        my_environment.events.my_event -= self.event_handler_func

Как ни странно, в конце запуска программы я получил следующую ошибку:

Exception AttributeError: "'NoneType' object has no attribute 'events'" in <bound method MyClass.__del__ of <myclass.MyClass instance at 0x04C54580>> ignored

Как такое могло быть ?! my_environment - это модуль, который я импортировал, почему это могло быть Нет? (events - это глобальный объект в нем с перехватчиками событий, такими как my_event)


person Jonathan    schedule 21.12.2011    source источник
comment
Как это обычно вызывается (кроме как при завершении программы)? Разве обработчик событий не будет содержать ссылку на объект, который предотвратит сборку мусора?   -  person interjay    schedule 21.12.2011
comment
@interjay - некоторые объекты MyClass существуют в течение всего цикла, а некоторые недолговечны. Я добавил эту очистку событий для более позднего случая.   -  person Jonathan    schedule 21.12.2011
comment
Я хочу сказать, что это никогда не будет вызываться для недолговечных объектов, потому что обработчик событий содержит ссылку на них.   -  person interjay    schedule 21.12.2011
comment
@interjay - хороший улов;) Я завел тупик в плане уничтожения этих объектов ...   -  person Jonathan    schedule 21.12.2011


Ответы (2)


Согласно документу Python о __del__:

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

Другими словами, когда для вашего объекта вызывается метод __del__, my_enviroment мог быть «удален» python, поэтому он может быть None ...

person Cédric Julien    schedule 21.12.2011

Если вы посмотрите документацию Python, вы увидите, что когда объекты завершаются, в конце программы, «механизм» уже разбирается. Это означает, что большая часть того, на что вы полагались, уже ушло - в данном случае глобальная переменная со ссылкой на модуль.

Что вам нужно сделать, так это убедиться, что ваши объекты, которые должны быть вызваны __del__, будут уничтожены до завершения программы - еще лучше, создайте менеджеры контекста с методами __enter__ и __exit__ и используйте их в операторах with. Или просто заключите свои предложения в __del__ внутри try-except блоков, чтобы они не вызывали исключения - если выполнение кода в них не критично на момент завершения программы.

person jsbueno    schedule 21.12.2011