0

For my repository class, I am creating an connection to the database when a function needs it (if None). I am using the __del__ to close the connection if not None. The object is guaranteed to be short lived.

I realized I am dependent on Ref counting to close the connection as soon as possible. I need the connection to be a field in the class because I am doing a select for update. The default python gc I read does ref counting at least the CPython implementation. But the pypy implementation has many different types of garbage collectors. Is it okay to rely on ref counting gc to close the connection as soon as possible? Or should I write a separate function and ensure that the connection is closed using a try finally block?

The class only consists of the connection field and two functions one to lock the table in database and select values and the other to update them.

This is my current implementation:

class ReserveRepository:
    def __init__(self):
        self.conn = None

    def select(self):
        cur = None
        try:
            self.conn = psycopg2.connect(config.DATABASE_URL)
            cur = self.conn.cursor()

            cur.execute('lock table sometable in ACCESS EXCLUSIVE mode')

            cur.execute('select id from sometable where condition')

            return list(map(lambda x: x[0]))
        finally:
            if cur is not None:
                cur.close()

    def update_quantities(self, id):
        cur = None
        try:
            if self.conn is None:
                self.conn = psycopg2.connect(config.DATABASE_URL)

            cur = self.conn.cursor()

            cur.execute('update sometable set column1 = value where id = %s', (id,))
            self.conn.commit()
            return reservation_id
        finally:
            if cur is not None:
                cur.close()

    def __del__(self):
        if self.conn is not None:
            self.conn.close()
            self.conn = None
Hemil
  • 916
  • 9
  • 27
  • Read also https://stackoverflow.com/questions/1481488/what-is-the-del-method-how-to-call-it for much more detailed answers. – Armin Rigo Aug 29 '20 at 15:40
  • Thanks @ArminRigo for the reference. C++ like destructors would have been great but try finally works as well. – Hemil Aug 30 '20 at 08:02

2 Answers2

2

tldr; The answer is no. Pypy does not implement reference counting as far as I understand. To demonstrate this, I made this simple program:

class Test:
    def __init__(self):
        print('__init__')

    def __del__(self):
        print('__del__')

t = Test()
print(t)

The output on CPython 3.8.2 is:

__init__
<__main__.Test object at 0x7f6e3bc13dc0>
__del__

However, the output on Pypy 7.3.1 (Python 3.6.9) is

__init__
<__main__.Test object at 0x00007f58325dfe88>

The __del__ function is not called.

Hemil
  • 916
  • 9
  • 27
0

Even on CPython, the answer is no. If the object is attached to a long-lived cached instance, __del__ will never be called. A better design pattern is to use a context manager for your object and do clean up at __exit__:

with make_a_connection(parameter) as conn:
    useconn(conn)
mattip
  • 2,360
  • 1
  • 13
  • 13