You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用__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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 16:24:27