Из чего проистекает эта ошибка, Экссептион Аттрибутееррор: ““NoneType' object существуешь не attribute '__ __'”?

Это пример относительно как на писания __del__:

#!/usr/bin/env python

class P(object):
    def __del__(self):
        print '__del__ work in P'


class C(P):  # class declaration
    def __init__(self): # contructor
        print 'initialized'

    def __del__(self): # destructor
        P.__del__(self) # call parent destructor
        print 'deleted'


c1 = C()
c2 = c1
c3 = c1
print 'all instance refer to the same object:', id(c1) == id(c2) == id(c3)
# del c1
# del c2
# del c3

Если я это скроллирую используя del для c1, c2 и c3, удаляются ссылки на эти инстанции и функционируй согласно ожидаемому.

Но если я комментирую последние 3 линии, я получаю эту ошибку, которую я не понимаю:

Exception AttributeError: "'NoneType' object has no attribute '__del__'" in <bound method C.__del__ of <__main__.C object at 0x1007b1fd0>> ignored

Как я могу решать это? и: Почему в конце концов он говорит ignored?

2
задан 19.08.2016, 09:51
2 ответа

В ответе kikocorreoso находится почему метод __del__ не удайся. Это отвечает частично на вопрос.

Ошибка вопроса происходит потому что: P уже он не существует, когда он пробуется P.__del__. После того, как не существовали P единственное, что существует, что-то из типа NoneType (None) и этот тип не располагает методом __del__. Отсюда исключение типа AttributeError

Происходи, потому что не существуют ссылки на класс P что поддержали живой класс. И хотя они были они могут быть удаленными во-первых. Ввиду того, что цикл стертого места ссылок в течение стертого места модуля не готов контролироваться, что возможно делать, состоит в том, чтобы захватывать исключение:

#!/usr/bin/env python
# -*- coding: utf-8; py-indent-offset:4 -*-
###############################################################################
from __future__ import (absolute_import, division, print_function,
                        unicode_literals)


class P(object):
    def __del__(self):
        print('__del__ work in P')


class C(P):  # class declaration
    def __init__(self):  # contructor
        print('initialized')

    def __del__(self):  # destructor
        try:
            P.__del__(self)  # call parent destructor
        except AttributeError:
            pass
        else:
            print('deleted')

c1 = C()
c2 = c1
c3 = c1
print('all instance refer to the same object:', id(c1) == id(c2) == id(c3))
# del c1
# del c2
# del c3

Так не случаются ошибки, потому что захватывается исключение. Было бы возможно прясть тоньше и делать один getattr на P метода __del__ чтобы гарантировать, что исключение AttributeError действительно он поэтому и не происходит внутри метода P.__del__ (потому что P.__del__ он мог бы производить исключение, которое распространилось бы и было бы захвачено блоком try / except / else в C.__del__)

3
ответ дан 24.11.2019, 13:37

Исключение происходит немного случайной формы?

В официальной документации Пайтона ты можешь читать следующие краткие содержания:

Заметьте: del x doesn’t directly call x.__del__() — the former decrements the reference count for x by one, and the latter is only called when x‘s reference count reaches zero. Some common situations that май prevent the reference count of an object from going to zero include: циркулировать references between objects (e.g., в doubly-linked list or в tree датируй structure with parent and child пойнтеров); в reference to the object on the stack frame of в function that caught an exception (the traceback stored in sys.exc_info() keeps the stack frame alive); or в reference to the object on the stack frame that raised an unhandled exception in интервключите mode (the traceback stored in sys.last_traceback keeps the stack frame alive). The first situation хан only be remedied by explicitly breaking the cycles; the second хан be решите by freeing the reference to the traceback object when it is не longer useful, and the third хан be решите by storing None in sys.last_traceback. Циркулировать references which пахало garbage пашите detected and cleaned up when the cyclic garbage collector is enabled (it’s on by default). Refer to the documentation for the gc модулируйте for обитайте information about this topic.

Смотри то, что находится в полужирном шрифте и италике в следующем кратком содержании:

Warning: Due to the precarious circumstances under which __del__() methods пашите invoked, exceptions that occur during their execution пашите ignored, and в warning is printed to sys.stderr instead. Also, when __del__() is invoked in response to в module being deleted (e.g., when execution of the program is подарите), other globals referenced by the __del__() method май already have been deleted or in the process of being torn down (e.g. the import machinery shutting down). For this reason, __del__() methods should do the absolute minimum needed to maintain external invariants. Starting with версия 1.5, Пайтон guarantees that globals whose ямс begins with в single underscore пахал deleted from their модулируйте before other globals пашите deleted; if не other references to such globals exist, this май help in assuring that imported модулируй пашите still available at the украдите when the __del__() method is called.

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

Относительно porqué выходит error/warning, когда ты получаешь в наследство P уже ты получаешь в наследство Ваш метод __del__, почему sobreescribirlo? Только он имеет смысл, если ты, кроме того, хочешь, чтобы метод сделал какую-то дополнительную вещь. С другой стороны, метод __del__ класса P, использованный, как ты это используешь, только благосклонно принятая инстанции класса P но self там это инстанция класса C. Отсюда error/warning. И поскольку он происходит внутри метода __del__ он проигнорирован.

1
ответ дан 24.11.2019, 13:37