cursor_factory=None 引发异常

0 投票
1 回答
1236 浏览
提问于 2025-04-18 04:13

我把我的 psycopg2 连接封装在一个叫 DB 的类里,其中有一个方法是用来获取游标的。我还在这个方法的参数里加了一个 cursor_factory,但是当我把默认值设为 None 时,就出现了错误。

class DB:

    ... connection code and other stuff ...

    def fetchcursor(self, query, params, in_cursor_factory=None):
        cur = self.conn.cursor(cursor_factory=in_cursor_factory)
        cur.execute(query, params)
        return cur

db = DB()
db.fetchcursor("SELECT * FROM foo", None)

我遇到的错误是:

TypeError: 'NoneType' object is not callable

当我把 None 换成 psycopg2.extras.DictCursor 时就没问题了。我想把默认值设为 None,正如文档中所说的那样:

cursor(name=None, cursor_factory=None, scrollable=None, withhold=False)

1 个回答

1

确实,看起来 connection.cursor() 的实现 在处理 cursor_factory 参数设置为 None 时表现得不太好。

这段代码没有检查 factory 是否被设置为 Py_None,而是直接调用了它。如果没有提供这个关键字参数,就会使用 connection.cursor_factory,根据源代码,这个默认值是 extensions.cursor(比如 psycopg2._psycopg.cursor)。

你可以通过测试是否为 None 来复现这个问题,并在这种情况下使用 connection.cursor_factory

def fetchcursor(self, query, params, in_cursor_factory=None):
    if in_cursor_factory is None:
        in_cursor_factory = self.conn.cursor_factory
    cur = self.conn.cursor(cursor_factory=in_cursor_factory)
    cur.execute(query, params)
    return cur

这假设你使用的是 psycopg 版本 2.5 或更新的版本;connection.cursor_factory 是在这个版本中新增的

对于之前的版本,只需使用 psycopg2._psycopg.cursor 来替代 self.conn.cursor_factory

撰写回答