DEBUG.WIKI
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
搬瓦工;先看线路,再选 VPS;CN2 GIA · 对应线路套餐;查看线路 →
V.PS:让项目靠近用户,亚太、欧洲、北美 KVM VPS

Pillow Path 给点赋列表时报 SystemError:改用坐标二元组

Pillow 13.0.0 的 Path 下标赋值按元组解析两个坐标,传列表可能出现 new style getargs 错误。将已校验的点写为二元组,并核对未修改的坐标与绘图结果。

Pillow 13.0.0 的 ImagePath.Path 可以构造出一条路径,但给某个点赋列表时可能报:

SystemError: new style getargs format but argument is not a tuple

例如,已有的 path 对象执行 path[0] = [1, 2] 会进入这条失败路径。它容易让人误以为 Pillow 二进制包损坏,因为创建路径时使用列表形式并不一定出错。

这里要区分构造路径和修改一个点。13.0.0 的下标赋值实现会把右侧对象直接交给只接受元组的 PyArg_ParseTuple(),按两个浮点坐标解析;传入列表时,底层返回了 SystemError。

将单个坐标明确写成二元组

点坐标已是经过业务校验的两个普通数值时,直接赋二元组即可:

from PIL import ImagePath

path = ImagePath.Path([(0, 0), (1, 1)])
path[0] = (1, 2)
print(path.tolist())

预期修改的是第一个点,第二个点仍为 (1, 1)。对于外部输入,先检查它确实包含两个坐标,再转换;不能用 tuple() 把任意数据都变成合法点。三维坐标、空序列、文本和无效数值应在应用的输入边界拒绝,不要让一个格式调整掩盖坏数据。

如果要替换整条路径,重新构造 ImagePath.Path 与逐点赋值也是不同操作。已有对象被其他绘图代码持有时,创建新对象不会自动改变旧引用;需要按调用关系传递新的路径。该对象也不支持切片赋值和点删除,不能将普通 Python 列表的全部修改方式照搬过来。

不要把其他坐标转换异常一起吞掉

这项处理只针对下标赋值右侧是列表、底层要求元组的情况。ImageDraw 读到不可转换的数值、特殊 Decimal 值等,可能进入另一条坐标转换路径;把外层所有异常都捕获为“跳过这一笔”,会让图形缺失而不易发现。

当前核对的最新正式版是 13.0.0,不能仅凭开发分支改动认定正式安装包已改变赋值行为。采用二元组是明确符合当前实现的调用方式,不需要修改 Pillow 的 C 扩展或重新编译整个项目。

复查时读取 path.tolist(),确认点数、顺序、被修改坐标及未修改坐标都符合预期,再把它交回原来的绘图流程。如果原始输入来自可恢复文件,保留原件并将输出保存到新位置;图像能保存并不能单独证明所有点都被正确绘制。