Consider the following example code
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)
Creating the object within the loop was intended to assure that the destructor of A would be called before the new A obj开发者_JAVA百科ect would be created. But apparently the following happens:
Initializing object 1
Initializing object 2
Deleting object 1
Deleting object 2
Why is the destructor of object 1 only called after the new object has been initialized? Is this an intended behaviour? I know that the for loop has no own scope in python. In C++, for example, the destructor of 1 would certainly be called before the constructor for object 2 (at least if the object is declared within the loop).
In my program I want to assure that the old object is deleted before the new one is created. Is there another possibility apart from deleting a
explicitly at the end of the for loop?
Thanks in advance.
Creation of the second object happens before the name is rebound and the first object is disposed of.
- The first
A
is instantiated. a
is bound.- The second
A
is instantiated. a
is rebound, and the firstA
is disposed of.- The program ends, and the second
A
is disposed of.
You can't rely on the garbage collector's implementation details when planning lifetime dependencies. You need to do this explicitly one way or another.
Context managers spring to mind, for example:
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)
This produces the following output:
Initializing object 1
Deleting object 1
Initializing object 2
Deleting object 2
Initializing object 1
Initializing object 2
Deleting object 1
Deleting object 2
Assuming that you want the object to be defined as its final value when the loop exits, don't delete the object explicitly at the end of the for loop, do so at the beginning of the loop, like this:
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)
That prints:
Initializing object 1
Deleting object 1
Initializing object 2
Deleting object 2
Initializing object 3
Deleting object 3
(Note: Ignatio is right about why it works the way it works, but KennyTM is right, too, that to make it more obvious what is happening you should make it go at least three times through the loop.)
精彩评论