python GC是否保证是引用计数垃圾回收器

问题描述

对于我的存储库类,我在有功能需要时(如果没有)创建与数据库的连接。如果不是“无”,我正在使用__del__关闭连接。该对象保证寿命很短。

我意识到我依赖于Ref来尽快关闭连接。我需要将连接作为类中的一个字段,因为我正在做select for update。我阅读的认python gc至少引用了cpython实现。但是pypy实现具有许多不同类型的garbage collectors。可以依靠引用计数gc尽快关闭连接吗?还是应该编写一个单独的函数并使用try finally块确保关闭连接?

该类仅包含连接字段和两个函数一个用于将表锁定在数据库中并选择值,另一个用于更新它们。

这是我当前的实现方式:

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

解决方法

tldr; 答案是否定。据我了解,Pypy没有实现引用计数。为了演示这一点,我编写了一个简单的程序:

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

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

t = Test()
print(t)

CPython 3.8.2的输出是:

__init__
<__main__.Test object at 0x7f6e3bc13dc0>
__del__

但是,Pypy 7.3.1(Python 3.6.9)的输出是

__init__
<__main__.Test object at 0x00007f58325dfe88>

未调用__del__函数。

,

即使在CPython上,答案也是。如果对象附加到了一个长期存在的缓存实例,则__del__将永远不会被调用。更好的设计模式是为您的对象使用上下文管理器,并在__exit__处进行清理:

with make_a_connection(parameter) as conn:
    useconn(conn)