2013-07-10 81 views
5

Khi tôi nhập thông tin này vào trình thông dịch, gọi 'y' dường như gọi hàm hủy?Tại sao hàm hủy python được gọi?

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

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

Đây là một lần chạy, đầu ra không có ý nghĩa với tôi.

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> 
>>> 

và khác, gọi 'del y' đôi khi gọi destructor và đôi khi không

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

Không thể trùng lặp. –

+1

Bạn có thể đăng đầu ra thực tế của tập lệnh không? – thegrinner

+0

Bạn có chắc chắn nó in "bị phá hủy" ở dòng này chứ không phải ở cuối tập lệnh không? – Dahaka

Trả lời

6

Bạn phải có thiết lập lại giá trị của y trong phiên dịch viên cùng, thả các tài liệu tham khảo tin cậy vào đối tượng ban đầu là 0. Sau đó, vì đối tượng đầu tiên không được tham chiếu, nên đối tượng mới bị hủy, nhưng đối tượng mới được tham chiếu bởi 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> 

Lưu ý rằng địa chỉ của hai đối tượng này là khác nhau. Các destroyed được in là khi __del__ được gọi trên trường hợp đầu tiên tại 0x00000000021A5608.

Trong ví dụ của bạn, khi bạn rõ ràng gọi del trên tham chiếu đối tượng, nó có thể bị tiêu diệt ngay lập tức (nếu đây là tài liệu tham khảo chỉ đến đối tượng và GC tìm thấy nó ngay lập tức). Khi bạn làm y = SmartPhone() đối tượng cũ có thể sẽ không bị phá hủy ngay lập tức, nhưng sẽ bị hủy khi bộ thu tìm thấy và thấy số tham chiếu 0. Điều này thường xảy ra gần như ngay lập tức nhưng có thể bị trì hoãn.

print 'destroyed' của bạn có thể được hiển thị ngay lập tức hoặc có thể hiển thị sau khi 1 hoặc nhiều lệnh bổ sung được thực thi trong phiên của bạn, nhưng sẽ diễn ra khá nhanh.

+0

Trong ví dụ thứ hai tôi đã đưa ra. Tại sao 'del y' không ngay lập tức gọi là destructor? – ppone

+0

Bởi vì có khả năng một tham chiếu tạm thời đến đối tượng ở những nơi khác chưa được xóa, như @falsetru chỉ ra trong câu trả lời của mình. – Brian

+2

Không có điều gì như "gọi' del' trên một đối tượng "trong Python. Như vậy, bạn không thể phá hủy một đối tượng ngay lập tức bằng 'del'. Những gì 'del' làm là để loại bỏ ** một tên **. Nghĩa là, nó loại bỏ ** một tham chiếu ** cho một đối tượng. Sau đó, khi bộ thu gom rác đi xung quanh và kiểm tra xem có bao nhiêu tham chiếu mà mỗi đối tượng có, nếu một đối tượng có tham chiếu không, thì nó chỉ bị phá hủy. Lưu ý rằng nếu bạn không gọi một cách rõ ràng bộ thu gom rác, nó sẽ tự do chạy bất cứ khi nào nó muốn, có thể ngay lập tức hoặc có thể là một thời gian sau đó. –

0

Tôi chạy cùng mã nhưng có một kết quả khác nhau:

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

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

Output:

>>> 
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 

thực del y làm công việc của mình nhưng bạn thay vì

>>> 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__ không phải là một destructor theo nghĩa C++. Nó là một phương pháp được bảo đảm để chạy trước khi phá hủy đối tượng, và sau khi một đối tượng trở nên có khả năng bị thu gom rác.

Trong CPython, điều này xảy ra khi số tham chiếu đạt 0. Theo đó, nếu bạn gán lại giá trị cho biến duy nhất đang giữ đối tượng với phương thức __del__, phương pháp đó sẽ được gọi ngay sau đó.

13

Kết quả được đề cập chỉ được sao chép trong trình bao tương tác.

Trong phiên tương tác, biến bổ sung _ tồn tại, tham chiếu đến giá trị cuối cùng.

Sử dụng sys.getrefcount để kiểm tra tính tham khảo:

>>> 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 sản lượng trên nên 1, 2. Chúng được in theo cách đó, bởi vì getrefcount() tăng số lượng tham chiếu tạm thời như được đề cập trong tài liệu getrefcount.


Tôi đã thay đổi SmartPhone như sau để dễ dàng kiểm tra những gì đang diễn ra.

>>> 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

Câu trả lời hay! Tôi không biết rằng _ tồn tại và có thể gây ra rắc rối như vậy. Tôi đang đăng một SmartPhone khác mà tôi đã sử dụng để thử nghiệm, nhưng đây là câu trả lời mà mọi người nên nhấp vào. – tdelaney

+3

+1 Giải thích rõ ràng – Brian

+2

+1 Câu trả lời hay! –

0

Mở rộng câu trả lời @ falsetru, đây là điện thoại thông minh giúp bạn dễ dàng xem điều gì đang xảy ra.

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 
>>> 
Các vấn đề liên quan