2016-09-01 5 views
1

Во время игры с OO Python я натолкнулся на следующее любопытство. Рассмотрим следующий простой класс:странное поведение деструктора python

>>> class Monty(): 
    def __init__(self): 
     print 'start m' 
    def __del__(self): 
     print 'deleted m' 

Инстанцирования объекта выходит, как и ожидался:

>>> a = Monty() 
start m 
>>> a 
<__main__.Monty instance at 0x7fdf9f084830> 

и теперь забавная часть:

>>> del a 
>>> a = Monty() 
start m 
>>> a 
deleted m 
<__main__.Monty instance at 0x7fdf9f083fc8> 
>>> a 
<__main__.Monty instance at 0x7fdf9f083fc8> 
>>> del a 
>>> a = Monty() 
start m 
>>> del(a) 
deleted m 
>>> a = Monty() 
start m 
>>> a 
deleted m 
<__main__.Monty instance at 0x7fdf9f084830> 

Запутанная частью здесь является то, что я получаю сообщение от деструктора с задержка. Мое понимание таково:

del a 

Удаляет ссылку на объект, чтобы объект a оставался для сбора мусора. Но почему-то интерпретатор ждет с передачей сообщения на консоль.

Другой это разница между

del x 

и

del(x) 

, так как если вы запускали код, используя последнее только все идет, как и ожидалось - вы получите немедленную информацию от деструктора.

Это можно воспроизвести на Python 2.7, а также с использованием Python 3.3.

ответ

3

Интерпретатор Python создает дополнительную ссылку . Каждый раз, когда выражение не возвращает None, результат отражается от и, хранящихся в встроенном имени _.

Когда вы затем повторяете другой результат, _ отскакивает от нового результата, а счетчик ссылок на старый объект падает. В вашем случае это означает, что только тогда является предыдущим Monty() экземпляр жатвы.

Другими словами, когда вы выполняете del a, вы не удаляете последнюю ссылку. Только тогда, когда вы позже выводящая ее нового объекта является последней ссылкой ушла:

>>> a = Monty() # reference count 1 
start m 
>>> a    # _ reference added, count 2 
<__main__.Monty instance at 0x7fdf9f084830>  
>>> del a   # reference count down to 1 again 
>>> a = Monty() 
start m 
>>> a    # _ now references the new object, count drops to 0 
deleted m   # so the old object is deleted. 
<__main__.Monty instance at 0x7fdf9f083fc8> 

Вы можете увидеть ссылку на вторя _, и вы можете очистить ссылку на вторя нечто совершенно несхожи

>>> a = Monty() # reference count 1 
start m 
>>> a    # echoing, so _ is set and count is now 2 
<__main__.Monty instance at 0x1056a2bd8> 
>>> _    # see, _ is referencing the same object 
<__main__.Monty instance at 0x1056a2bd8> 
>>> del a   # reference count down to 1 
>>> _    # _ is still referencing the result 
<__main__.Monty instance at 0x1056a2bd8> 
>>> 'some other expression' # point to something else 
deleted m      # so reference count is down to 0 
'some other expression' 
>>> _ 
'some other expression' 

Нет никакой разницы между del x и del(x). Оба выполняют оператор del, скобки являются частью выражения и в этом случае не являются операциями. Нет функции del().

Реальная разница в том, что вы не эхо a в той части кода, так что не были созданы дополнительные _ ссылки.

Вы бы получить те же результаты Wether или не использовать (..) круглые скобки:

>>> a = Monty() # ref count 1 
start m 
>>> del a  # no _ echo reference, so count back to 0 
deleted m 
>>> a = Monty() # ref count 1 
start m 
>>> del(a)  # no _ echo reference, so count back to 0 
deleted m 
+0

Пожалуйста, вы можете подробно остановиться на разнице между вызовом: дель X и называют: дель (X)? – data

+1

@data: нет разницы. У вас есть 'del', за которым следует выражение *, создающее объект для удаления. '(..)' круглые скобки являются частью выражения. –

+2

@data: Если вы считаете, что видите различия между поведением 'del X' и' del (X) ', эти различия были фактически вызваны тем, какое значение вы в конечном итоге вызывали для Python для хранения на' _'. – user2357112

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