2013-07-10 12 views
5

Kiedy wpiszesz to do interpretera, wywołanie "y" wydaje się wywoływać destruktor?Dlaczego wywoływany jest python destructor?

class SmartPhone: 
    def __del__(self): 
     print "destroyed" 

y = SmartPhone() 
y #prints destroyed, why is that? 
y #object is still there 

Oto jeden przebieg, wyjście nie ma dla mnie sensu.

C:\Users\z4>python 
Python 2.7.3 (default, Apr 10 2012, 23:31:26) [MSC v.1500 32 bit (Intel)] on win 
32 
Type "help", "copyright", "credits" or "license" for more information. 
>>> class SmartPhone: 
...  def __del__(self): 
...  print "destroyed" 
... 
>>> y = SmartPhone() 
>>> del y 
destroyed 
>>> y = SmartPhone() 
>>> y 
<__main__.SmartPhone instance at 0x01A7CBC0> 
>>> y 
<__main__.SmartPhone instance at 0x01A7CBC0> 
>>> y 
<__main__.SmartPhone instance at 0x01A7CBC0> 
>>> del y 
>>> y = SmartPhone() 
>>> y 
destroyed 
<__main__.SmartPhone instance at 0x01A7CB98> 
>>> 

i innym, nazywając „del y” czasami wywołuje destruktor, a czasami nie

C:\Users\z4>python 
Python 2.7.3 (default, Apr 10 2012, 23:31:26) [MSC v.1500 32 bit (Intel)] on win 
32 
Type "help", "copyright", "credits" or "license" for more information. 
>>> class SmartPhone: 
...  def __del__(self): 
...    print "destroyed" 
... 
>>> 
>>> y = SmartPhone() 
>>> 
>>> y 
<__main__.SmartPhone instance at 0x01B6CBE8> 
>>> y 
<__main__.SmartPhone instance at 0x01B6CBE8> 
>>> y 
<__main__.SmartPhone instance at 0x01B6CBE8> 
>>> del y 
>>> y 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
NameError: name 'y' is not defined 
>>> y = SmartPhone() 
>>> y 
destroyed 
<__main__.SmartPhone instance at 0x01B6CC38> 
>>> del y 
>>> y 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
NameError: name 'y' is not defined 
>>> 
+14

Nie można powielić. –

+1

Czy możesz opublikować rzeczywiste wyniki skryptu? – thegrinner

+0

Czy jesteś pewien, że drukuje "zniszczony" w tym wierszu, a nie na końcu skryptu? – Dahaka

Odpowiedz

6

Musisz mieć zresetować wartość y w tej samej sesji interpretera, zrzucając liczyć na odniesienie oryginalny obiekt do 0. Wtedy, ponieważ pierwszy obiekt nie jest wymieniony, to zostanie zniszczone, ale nowy obiekt odwołuje y

>>> class SmartPhone: 
... def __del__(self): 
...  print 'destroyed' 
... 
>>> y = SmartPhone() 
>>> y 
<__main__.SmartPhone instance at 0x00000000021A5608> 
>>> y = SmartPhone() 
>>> y 
destroyed 
<__main__.SmartPhone instance at 0x00000000021A5648> 

Należy zauważyć, że adres tych dwóch obiektów jest inny. Wydrukowany jest destroyed, gdy __del__ jest wywoływany w pierwszym wystąpieniu pod numerem 0x00000000021A5608.

W przykładzie, kiedy jawnie wywołać del na odwołania do obiektu, to może zostać zniszczona natychmiast (jeśli było to jedyne odniesienie do obiektu i GC Znaleziono go natychmiast). Kiedy wykonasz y = SmartPhone() stary obiekt prawdopodobnie nie zostanie natychmiast zniszczony, ale zostanie zniszczony, gdy kolektor go znajdzie i zobaczy liczbę referencyjną 0. Zdarza się to prawie natychmiast, ale może być opóźnione.

Twoja print 'destroyed' może być wyświetlana natychmiast lub może być wyświetlana po wykonaniu co najmniej jednego dodatkowego polecenia w sesji, ale powinna nastąpić dość szybko.

+0

W drugim przykładzie dałem. Dlaczego "del y" nie od razu wywołuje destruktor? – ppone

+0

Ponieważ było prawdopodobne tymczasowe odniesienie do obiektu w innym miejscu, które nie zostało wyczyszczone, jak @falsetru wskazuje w swojej odpowiedzi. – Brian

+2

Nie ma czegoś takiego jak "wywołanie' del' na obiekcie "w Pythonie. Jako takie, nie można zniszczyć obiektu natychmiast za pomocą 'del'. Czym jest "del", to usunąć ** nazwę **. Oznacza to, że usuwa on ** odwołanie ** do obiektu. Następnie, gdy pojemnik na śmieci obraca się i sprawdza, ile odniesień ma każdy obiekt, jeśli obiekt ma zerowe referencje, zostaje tylko zniszczony. Zwróć uwagę, że jeśli nie wywołasz w sposób jawny kosza, możesz go uruchomić, kiedy tylko zechce, co może nastąpić od razu lub może za jakiś czas. –

0

wpadłem sam kod, ale dostał inny wynik:

class SmartPhone: 
    def __del__(self): 
     print "destroyed" 

y = SmartPhone() 
del y 
print y #prints destroyed, why is that? 

wyjściowa:

>>> 
destroyed 

Traceback (most recent call last): 
    File "C:/Users/Kulanjith/Desktop/rand.py", line 7, in <module> 
    print y #prints destroyed, why is that? 
NameError: name 'y' is not defined 

faktycznie del y wykonuje swoją pracę, ale zamiast tego

>>> y = SmartPhone() # create object 
>>> del y # delete's the object y, therefore no variable exist after this line executes 
destroyed 
>>> y = SmartPhone() # again creates a object as a new variable y 
>>> y # since no __repr__ methods are define the outcome is normal 
<__main__.SmartPhone instance at 0x01A7CBC0> 
0

__del__ nie jest destruktor w sensie C++. Jest to metoda, która gwarantuje, że zostanie uruchomiona przed zniszczeniem obiektu i po tym, jak obiekt stanie się zdolny do zbierania śmieci.

W CPython dzieje się to, gdy licznik odniesień osiągnie 0. Odpowiednio, jeśli ponownie przypiszesz wartość do pojedynczej zmiennej trzymającej obiekt za pomocą metody __del__, ta metoda tego obiektu zostanie wkrótce wywołana.

13

Dane wyjściowe są replikowane tylko w powłoce interaktywnej.

W sesji interaktywnej istnieje dodatkowa zmienna _, która odnosi się do ostatniej wartości.

Korzystanie sys.getrefcount do sprawdzenia licznika odwołań:

>>> import sys 
>>> class SmartPhone: 
...  def __del__(self): 
...  print "destroyed" 
... 
>>> y = SmartPhone() 
>>> sys.getrefcount(y) # not printed, _ does not reference SmartPhone object yet. 
2 
>>> y 
<__main__.SmartPhone instance at 0x000000000263B588> 
>>> sys.getrefcount(y) # y printed, _ reference SmartPhone object. 
3 

2, 3 podano wyjścia powinien być 1, 2. Są drukowane w ten sposób, ponieważ getrefcount() zwiększa tymczasowo liczbę odwołań tymczasowo, jak wspomniano w dokumentacji getrefcount.


Zmieniłem SmartPhone w następujący sposób, aby ułatwić sprawdzenie, co się dzieje.

>>> class SmartPhone(object): 
...  def __init__(self, name): 
...   self.name = name 
...  def __repr__(self): 
...   return super(SmartPhone, self).__repr__() + ' name=' + self.name 
...  def __del__(self): 
...  print "destroyed", self 
... 
>>> y = SmartPhone('first') 
>>> del y # deleted immediately, because only "y" reference it. 
destroyed <__main__.SmartPhone object at 0x00000000024FEFD0> name=first 
>>> y = SmartPhone('second') 
>>> y # at this time, _ reference to second y (y's reference count is now 2) 
<__main__.SmartPhone object at 0x00000000024FEFD0> name=second 
>>> y 
<__main__.SmartPhone object at 0x00000000024FEFD0> name=second 
>>> y 
<__main__.SmartPhone object at 0x00000000024FEFD0> name=second 
>>> del y # not deleted immediately, because _ reference it. 
>>> y = SmartPhone('third') # _ still reference the second y, because nothing is printed. 
>>> y # second y is deleted, because _ now reference the third y. (no reference to the second y) 
destroyed <__main__.SmartPhone object at 0x00000000024FEFD0> name=second 
<__main__.SmartPhone object at 0x000000000264A470> name=third 
+2

Świetna odpowiedź! Nie miałem pojęcia, że ​​_ istnieje i może powodować takie kłopoty. Zamieszczam inny SmartPhone, który użyłem do eksperymentowania, ale to jest odpowiedź, którą każdy powinien kliknąć. – tdelaney

+3

+1 Dobrze wyjaśniony – Brian

+2

+1 Świetna odpowiedź! –

0

Rozszerzając użytkownika @ falsetru odpowiedź, oto smartphone, który sprawia, że ​​łatwo zobaczyć, co się dzieje.

myid = 0 

class SmartPhone(object): 
    def __init__(self): 
     global myid 
     self.myid = myid 
     print("init %d" % self.myid) 
     myid += 1 
    def __del__(self): 
     print("delete", self) 
    def __repr__(self): 
     return "repr %d" % self.myid 
    def __str__(self): 
     return "str %d" % self.myid 

>>> 
>>> y=SmartPhone() 
init 0 
>>> # _ will hold a ref to y 
... 
>>> 
>>> y 
repr 0 
>>> _ 
repr 0 
>>> # del only decreases the ref count 
... 
>>> del y 
>>> _ 
repr 0 
>>> # _ still refs 0 
... 
>>> y=SmartPhone() 
init 1 
>>> # but now i reassign _ and 0 goes away 
... 
>>> y 
delete str 0 
repr 1 
>>> 
Powiązane problemy