在对象的第二次初始化时,为什么在__del__之前调用__init__?

时间:2011-04-18 12:34:05

标签: python oop

考虑以下示例代码

class A:
    def __init__(self, i):
        self.i = i
        print("Initializing object {}".format(self.i))

    def __del__(self):
        print("Deleting object {}".format(self.i))

for i in [1, 2]:
    a = A(i)

在循环中创建对象的目的是确保在创建新的A对象之前调用A的析构函数。但显然会发生以下情况:

  

初始化对象1

     

初始化对象2

     

删除对象1

     

删除对象2

为什么对象1的析构函数只在新对象初始化后才被调用?这是预期的行为吗?我知道for循环在python中没有自己的作用域。例如,在C ++中,在对象2的构造函数之前肯定会调用1的析构函数(至少如果在循环中声明了对象)。

在我的程序中,我想确保在创建新对象之前删除旧对象。除了在for循环结束时显式删除a之外还有其他可能吗?

提前致谢。

3 个答案:

答案 0 :(得分:11)

第二个对象的创建发生在名称反弹并且第一个对象被丢弃之前。

  1. 第一个A已实例化。
  2. a受约束。
  3. 第二个A已实例化。
  4. a被反弹,第一个A被处理掉。
  5. 程序结束,第二个A被处理掉。

答案 1 :(得分:9)

在规划生命周期依赖关系时,您不能依赖垃圾收集器的实现细节。你需要以这种或那种方式明确地做到这一点。

上下文管理者会想到,例如:

from contextlib import contextmanager

@contextmanager
def deleting(obj):
    try:
        yield
    finally:
        del(obj)

class A:
    def __init__(self, i):
        self.i = i
        print("Initializing object {}".format(self.i))

    def __del__(self):
        print("Deleting object {}".format(self.i))

for i in [1,2]:
    with deleting(A(i)) as obj:
        pass

print

for i in [1,2]:
    a = A(i)

这会产生以下输出:

Initializing object 1
Deleting object 1
Initializing object 2
Deleting object 2

Initializing object 1
Initializing object 2
Deleting object 1
Deleting object 2

答案 2 :(得分:0)

假设您希望在循环退出时将对象定义为其最终值,请不要在for循环的 end 处明确删除对象,请在处执行此操作开始循环,如下所示:

class A:
    def __init__(self, i):
        self.i = i
        print("Initializing object {}".format(self.i))

    def __del__(self):
        print("Deleting object {}".format(self.i))

for i in [1, 2, 3]:
    a = None
    a = A(i)

打印:

Initializing object 1
Deleting object 1
Initializing object 2
Deleting object 2
Initializing object 3
Deleting object 3

(注意:Ignatio对于它的工作原理是正确的,但是KennyTM也是正确的,为了使发生的事情变得更加明显,你应该让它在循环中至少进行三次。)