I have an object with an internal database connection that's active throughout its lifetime. At the end of the program's run, the connection has to be committed and closed. So far I've used an explicit close
method, but this is somewhat cumbersome, especially when exceptions can happen in the calling code.
I'm considering using the __del__
method for closing, but after some reading online I have concerns. Is this a valid usage pattern? Can I be sure that the internal resources will be freed in __del__
correctly?
This discussion raised a similar question but found no satisfactory answer. I don't want to have an explicit close
method, and using with
isn't an option, because my object isn't used as simply as open-play-close, but is kept as a member of another, larger object, that uses it while running in a GUI.
C++ has perfectly working destructors where one can free resources safely, so I would imagine Python has something agreed-upon too. For some reason it seems not to be the case, and many in the community vow against __del__
. What's the alternative, then?
To delete an object in Python, we use the 'del' keyword. A when we try to refer to a deleted object, it raises NameError.
Create Destructor using the __del__() Method This method is automatically called by Python when the instance is about to be destroyed. It is also called a finalizer or (improperly) a destructor.
Using the __del__() method. In Python, a destructor is defined using the specific function __del__(). For instance, when we run del object name, the object's destructor is automatically called, and it then gets garbage collected.
The __del__() method is a known as a destructor method. It is called when an object is garbage collected which happens after all references to the object have been deleted.
Read up on the with statement. You're describing its use case.
You'll need to wrap your connection in a "Context Manager" class that handles the __enter__
and __exit__
methods used by the with
statement.
See PEP 343 for more information.
Edit
"my object isn't used as simply as open-play-close, but is kept as a member of another, larger object"
class AnObjectWhichMustBeClosed( object ):
def __enter__( self ):
# acquire
def __exit__( self, type, value, traceback ):
# release
def open( self, dbConnectionInfo ):
# open the connection, updating the state for __exit__ to handle.
class ALargerObject( object ):
def __init__( self ):
pass
def injectTheObjectThatMustBeClosed( self, anObject ):
self.useThis = anObject
class MyGuiApp( self ):
def run( self ):
# build GUI objects
large = ALargeObject()
with AnObjectWhichMustBeClosed() as x:
large.injectTheObjectThatMustBeClosed( x )
mainLoop()
Some folks call this "Dependency Injection" and "Inversion of Control". Other folks call this the Strategy pattern. The "ObjectThatMustBeClosed" is a strategy, plugged into some larger object. The assembly is created at a top-level of the GUI app, since that's usually where resources like databases are acquired.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With