2016-05-02 6 views
3

При попытке понять некоторые концепции Python, я столкнулся со следующей проблемой:деструктор, вызываемый при невозможности создать экземпляр?

class A: 
    def __init__(self, x): 
     self.x = x 

    def __del__(self): 
     print("del") 

a1 = A() 

выходы:

$ python test.py 
del 
Traceback (most recent call last): 
    File "testdest.py", line 9, in <module> 
    a1 = A() 
TypeError: __init__() takes exactly 2 arguments (1 given) 

ошибка очевидна (отсутствует аргумент при инстанцировании), но мне интересно почему деструктора вызывается перед тем, как иметь экземпляр?

Если это не попытка создания экземпляра, Python создает экземпляр еще до вызова конструктора и его нужно будет очистить в конце?

С self передается конструктору, могу ли я предположить, что это self является экземпляром? Это правда, тогда экземпляр уже существует при вызове конструктора, верно?

Это поведение сборщика мусора, которое может зависеть от текущей реализации?

+0

Я могу ошибаться, но я обычно думаю о '__del__', как похожий на' finally' пункта, то есть то, что не выполняется «независимо от того, что». – Kris

+1

@ Kris Вид. Однако нет никакой гарантии, что '__del__' будет вызван для экземпляров, которые все еще живут, когда переводчик завершает работу. – chepner

ответ

5

Из документации Python:

Объекты никогда не явно уничтожены; однако, когда они становятся недоступными, они могут быть собраны в мусор. Реализация разрешено откладывать сборку мусора или вообще ее пропускать - это вопрос качества реализации, так как сборка мусора реализована до тех пор, пока не собраны никакие объекты, которые до сих пор остаются достижимыми.

object.__init__(self[, ...]) 

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

object.__del__(self) 

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

Так экземпляр объекта уже существует, когда __init__ называется, так как он создается __new__. Но для Python вообще нет гарантии, что __del__ когда-либо будет вызван.

Следующие действия применимы только к CPython, эталонной реализации Python.

Примечание (для object.__del__(self))

дель х непосредственно не call x.__del__() - бывшие декрементирует счетчик ссылок х на единицу, а последняя называется только тогда, когда иксы счетчик ссылок достигает нуля , [...]

Здесь __del__ вызывается всякий раз, когда счетчик ссылок для экземпляра падает до 0. Это не имеет никакого отношения к сбору мусора.Небольшой эксперимент:

>>> class A: 
... def __del__(self): print "del" 
... 
>>> a = A() 
>>> a = None 
del 
>>> import gc 
>>> gc.disable() 
>>> a = A() 
>>> a = None 
del 

Как вы можете видеть, деструктор вызывается даже тогда, когда GC явно отключен.

Обратите внимание, что это также означает, что если у вас есть циклы в иерархии объектов, вы получаете объекты, для которых __del__ никогда не вызывается, так как Python GC не может справляться с эталонными циклами.

>>> a1 = A() 
>>> a2 = A() 
>>> a1.x = a2 
>>> a2.x = a1 
>>> a1 = None 
>>> a2 = None 
>>> import gc 
>>> gc.collect() 
4 
>>> gc.garbage 
[<__main__.A instance at 0x7f2c66a1d7e8>, <__main__.A instance at 0x7f2c66a1d830>] 
+2

* "И' __del__' вызывается всякий раз, когда счетчик ссылок для экземпляра падает до 0. "* ... и над ним запускает сборщик мусора. * Когда * это происходит, зависит от алгоритма, используемого интерпретатором Python, который отличается от реализации до реализации. В крайних случаях это может даже не произойти вообще, пока вся программа не выйдет. –

+0

@Markus Я нахожу ваш ответ очень интересным, но мне просто нужно объяснение вашего последнего предложения, которое я не совсем понимаю: * «всякий раз, когда счетчик ссылок для экземпляра падает до 0». *. Я могу сказать что-то глупое, но означает ли это * «всякий раз, когда экземпляр больше не привязан к переменной». *? – vmonteco

+1

@vmonteco Посмотрите на https://docs.python.org/2/reference/datamodel.html#object.__del__. Отвечает ли это на ваш вопрос? – Markus

Смежные вопросы