First let me acknowledge that a good discussion already exists here: How do I correctly clean up a Python object?
I'm trying to improve efficiency of a bit of code that currently is schematically like this:
import psycopg2
class StuffHandler:
def __init__(self, db_credentials):
self.db_credentials = db_credentials
def handle(self, stuff):
try:
with psycopg2.connect(self.db_credentials) as conn:
with conn.cursor() as cursor:
cursor.execute( < write stuff to database > )
except psycopg2.DataError as e:
logger.error(e)
finally:
conn.close()
As you see, this is correct, but it unnecessarily open and closes a database connection every time, which I'm trying to improve.
The code above is used by the application in the following way, schematically:
h = StuffHandler(db_credentials)
my_obj.set_stuff_handler(h)
I want this object to hold a long-lived connection, and schematically I think it should work like this
import psycopg2
class Handler:
def __init__(self, db_credentials):
self.conn = psycopg2.connect(db_credentials)
def handle(self, stuff):
# TODO: check that connection is still alive, but those are
# details don't matter for this discussion
try:
with self.conn.cursor() as cursor:
cursor.execute( < write stuff to database > )
except psycopg2.DataError as e:
logger.error(e)
The question is: in Python, how do I correctly clean up resources? That includes closing the connection, but also things like if I want to add a buffer, flush the buffer, etc.
According to the marked-as-correct and vastly more updated answer, https://stackoverflow.com/a/865272/12595391, the answer is: add methods __enter__
and __exit__
so that this class can be used as a context. I imagine that this means:
def __enter__(self):
return self
def __exit__(exc_type, exc_value, traceback):
self.conn.close()
So now my question becomes: what if I don't want to use contexts? What if I DON'T want to do
with StuffHandler(db_credentials) as h:
my_obj.set_stuff_handler(h)
but instead I don't want to touch the application code?
In the question mentioned above, an alternative is described in this answer: https://stackoverflow.com/a/41627098/12595391 where they suggest registering a cleanup methods using atexit.register()
. Isn't this vastly more appropriate for my situation? What are the downsides of this approach? The commenter @hlongmore seems to mention a downside but I don't really understand what he meant.
Thanks for the help.