为什么要调用python析构函数?

时间:2013-07-10 15:01:21

标签: python

当我在翻译中输入此内容时,请拨打' y'似乎调用了析构函数?

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

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

这是一次运行,输出对我没有意义。

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

和另一个,打电话给&#39; del y&#39;有时称为析构函数,有时不会

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

5 个答案:

答案 0 :(得分:13)

有问题的输出仅在交互式shell中复制。

在交互式会话中,存在附加变量_,它引用最后一个值。

使用sys.getrefcount检查引用计数:

>>> 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
上面输出中的

23应为12。它们以这种方式打印,因为getrefcount()会暂时增加引用计数,如getrefcount文档中所述。


我按照以下方式更改了SmartPhone,以便于检查正在发生的事情。

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

答案 1 :(得分:6)

您必须在同一个解释器会话中重置y的值,将原始对象的引用计数丢弃为0.然后,由于未引用第一个对象,它将被销毁,但是新对象由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>

请注意,这两个对象的地址不同。打印的destroyed是在__del__的第一个实例上调用0x00000000021A5608时。

在您的示例中,当您在对象引用上显式调用del时,可能会立即被销毁(如果这是对象的唯一引用并且发现了GC它立即)。当你执行y = SmartPhone()时,旧对象可能不会立即被销毁,但是当收集器找到它并且看到引用计数为0时将被销毁。这通常会立即发生,但可能会被延迟。

您的print 'destroyed'可能会立即显示,也可能会在您的会话中执行一个或多个其他命令后显示,但应该会很快发生。

答案 2 :(得分:0)

我运行了相同的代码但得到了不同的结果:

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

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

输出:

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

实际上del y完成了它的工作,但你取而代之的是

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

答案 3 :(得分:0)

__del__不是C ++意义上的析构函数。这是一种保证在对象销毁之前运行的方法,并且在对象变得能够被垃圾收集之后运行。

在CPython中,当引用计数达到0时会发生这种情况。因此,如果将值重新分配给包含__del__方法的对象的单个变量,则此后不久将调用该对象的该方法。

答案 4 :(得分:0)

扩展@fattru的答案,这是一个智能手机,可以很容易地看到发生了什么。

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