使用__slots__实例调用mogrify抛出SystemError错误求助
解决psycopg2 mogrify调用自定义Row类时的SystemError问题
问题根源
你的自定义Row类存在两个关键问题,导致mogrify调用失败:
__setitem__方法实现错误:setattr(name, value)应该改为setattr(self, name, value),否则会尝试给字符串name设置属性,而非当前实例。- 未实现序列类型必需的
__len__方法:mogrify处理序列类参数时,需要通过__len__确认参数数量,缺少该方法会触发底层C代码的参数错误。
修复后的Row类实现
修正上述问题,并补充必要的序列方法,让Row实例能被mogrify正确识别:
def define_row(fields): fields_tuple = tuple(fields) class Row: __slots__ = fields_tuple def __init__(self): for attr in self.__slots__: setattr(self, attr, None) def __setitem__(self, name, value): # 修复:操作当前实例的属性 setattr(self, name, value) def __getitem__(self, i): return getattr(self, self.__slots__[i]) def __len__(self): # 补充序列必需的长度方法 return len(self.__slots__) return Row
替代方案:使用dataclass更简洁
如果不需要严格基于__slots__,Python 3.7+的dataclasses可以更优雅地实现「带默认None的可变数据类」,且天然支持转成tuple供mogrify使用:
from dataclasses import dataclass, fields as dc_fields def define_row(fields): # 动态生成dataclass,每个字段默认值为None cls_kwargs = {field: None for field in fields} cls_kwargs['__annotations__'] = {field: type(None) for field in fields} @dataclass class Row: pass for field, default in cls_kwargs.items(): setattr(Row, field, default) # 添加转tuple的方法,方便mogrify调用 def to_tuple(self): return tuple(getattr(self, f.name) for f in dc_fields(self)) Row.to_tuple = to_tuple return Row # 使用时直接转tuple传入mogrify args_str = ",".join( cur.mogrify(placeholders, r.to_tuple()).decode("utf-8") for r in rows )
关于mogrify的参数类型
mogrify的parameters参数支持两种类型:
- 序列类型(tuple/list/自定义序列):对应位置占位符
%s,需要实现__len__和__getitem__(按整数索引访问)。 - 映射类型(dict/自定义映射):对应命名占位符
%(name)s,需要实现__getitem__(按键访问)。
内容的提问来源于stack exchange,提问作者Shiva
相关产品推荐
相关产品推荐

