Source From Here
Question
Consider code below:
__del__(self) above fails with an AttributeError exception. I understand Python doesn't guarantee the existence of "global variables" (member data in this context?) when __del__() is invoked. If that is the case and this is the reason for the exception, how do I make sure the object destructs properly?
How-To
I'd recommend using Python's with statement for managing resources that need to be cleaned up. The problem with using an explicit close() statement is that you have to worry about people forgetting to call it at all or forgetting to place it in a finally block to prevent a resource leak when an exception occurs.
To use the with statement, create a class with the following methods:
In your example above, you'd use:
Then, when someone wanted to use your class, they'd do the following:
The variable myObj will be an instance of type
MyClass (it's the value returned by the __enter__ method). Its __exit__ method will automatically be called, regardless of whether or not an exception occurs. Below is the output:
You could even take this approach a step further. In the example above, someone could still instantiate MyClass using its constructor without using the with clause. You don't want that to happen. You can fix this by creating a MyClassResource class that defines the __enter__ and __exit__ methods. Then, the Package class would be defined strictly inside the __enter__ method and returned. That way, the caller never could instantiate the MyClass class without using a with statement:
You'd use this as follows:
The output looks like:
Question
Consider code below:
- class MyClass:
- def __init__(self):
- self.files = []
- # ...
- def __del__(self):
- for file in self.files:
- os.unlink(file)
How-To
I'd recommend using Python's with statement for managing resources that need to be cleaned up. The problem with using an explicit close() statement is that you have to worry about people forgetting to call it at all or forgetting to place it in a finally block to prevent a resource leak when an exception occurs.
To use the with statement, create a class with the following methods:
- def __enter__(self)
- def __exit__(self, exc_type, exc_value, traceback)
- import os
- class MyClass:
- def __init__(self):
- print "Initialize %s" % (self.__class__.__name__)
- self.files = []
- def __enter__(self):
- print "Enter %s" % (self.__class__.__name__)
- return self
- # ...
- def __exit__(self, exc_type, exc_value, traceback):
- print "Exit %s" % (self.__class__.__name__)
- for file in self.files:
- os.unlink(file)
- print "Outside with"
- with MyClass() as myObj:
- # Use myObj
- print "Inside with"
- pass
- print "Exit with"
You could even take this approach a step further. In the example above, someone could still instantiate MyClass using its constructor without using the with clause. You don't want that to happen. You can fix this by creating a MyClassResource class that defines the __enter__ and __exit__ methods. Then, the Package class would be defined strictly inside the __enter__ method and returned. That way, the caller never could instantiate the MyClass class without using a with statement:
- class MyClassResource:
- def __enter__(self):
- class MyAnotherClass:
- def __init__(self):
- pass
- def cleanup(self):
- pass
- print "Enter %s" % (self.__class__.__name__)
- self.myObj = MyAnotherClass()
- return self.myObj
- # ...
- def __exit__(self, exc_type, exc_value, traceback):
- print "Exit %s" % (self.__class__.__name__)
- self.myObj.cleanup()
- # Below will throw Exception NameError
- #myAnoObj = MyAnotherClass()
- with MyClassResource() as myObj:
- # Use myObj which is instance of MyAnotherClass
- print "myObj is %s" % (myObj.__class__.__name__)
沒有留言:
張貼留言