如何扩展psycopg2 cursor类的__iter__方法实现迭代后自动关连接?
问题分析与解决方案
递归错误原因
你遇到的RecursionError是因为psycopg2的cursor类的__iter__方法返回的是游标实例本身(self),而非独立迭代器。当你在子类中用yield from super().__iter__()时,super().__iter__()返回的是你的AutoCloseCur实例,会再次触发子类的__iter__方法,形成无限递归。
正确的自定义游标实现
你需要重写__next__方法而非__iter__,通过捕获StopIteration异常判断迭代是否耗尽,再执行关闭操作:
class AutoCloseCur(psycopg2.extensions.cursor): def __next__(self): try: # 调用父类的__next__获取下一行数据 return super().__next__() except StopIteration: # 迭代耗尽,关闭游标和连接 self.close() self.connection.close() # 必须重新抛出StopIteration,否则迭代器无法正常终止 raise
你的疑问解答
继承类是否正确?
是的,psycopg2.extensions.cursor就是psycopg2游标类的正确基类,继承它没有问题。是否需要重写其他魔法方法?
针对迭代场景,重写__next__就足够。如果你的代码中还有直接调用fetchone()、fetchmany()等方法的场景,可以封装这些方法,在返回空结果时执行关闭操作,但迭代场景下无需额外重写其他方法。psycopg2是否有内置功能?
psycopg2本身没有提供迭代耗尽自动关闭连接的内置功能,但官方推荐使用**上下文管理器(with语句)**管理连接和游标生命周期:with psycopg2.connect(...) as conn: with conn.cursor(name='server-side-cursor') as cur: cur.execute("SELECT ...") for row in cur: # 处理数据上下文管理器会在代码块结束时自动关闭游标和连接,无需手动调用
close()。不过如果你更倾向于自定义游标类的方式,前面的实现完全可行。
注意:如果多个游标共享同一个数据库连接,迭代耗尽后关闭连接会影响其他游标,这种场景下建议不要在游标中关闭连接,而是单独管理连接的生命周期。
内容的提问来源于stack exchange,提问作者Shiva
相关产品推荐
相关产品推荐

