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

Python动态数组测试用例偶发ValueError: PyObject is NULL问题排查

偶发ValueError: PyObject is NULL问题排查与修复

问题场景

用ctypes实现带类型的Python动态数组,运行指定测试用例时偶尔抛出ValueError: PyObject is NULL,错误并非每次运行都会出现。

实现代码

import ctypes

class DynamicArray:

  def __init__(self,):
    self.n = 0 # 当前已添加元素数量
    self.capacity = 1 # 初始容量为1
    self.array    = self.make_array(self.capacity)

  def add_element(self,element):
    # 检查数组是否已满
    if self.n == self.capacity:
      self.resize(2*self.capacity)
    
    self.array[self.n] = element
    self.n +=1 

    return 

  def resize(self,new_capacity):
    new_array = self.make_array(new_capacity)

    for i in range(self.n):
      new_array[i] = self.array[i]

    self.array = new_array
    self.capacity = new_capacity
    return 

  def make_array(self,capacity):
    return (capacity * ctypes.py_object)()

  def get_array(self):
    return list(self.array)

测试用例

dynamic_r = DynamicArray()
dynamic_r.add_element(4)
dynamic_r.get_array()
dynamic_r.add_element(9)
dynamic_r.get_array()
dynamic_r.add_element(10)
dynamic_r.get_array()

报错信息

ValueError: PyObject is NULL

问题原因

问题出在get_array方法:list(self.array)会遍历整个ctypes数组的所有容量位置,而不仅仅是已添加的self.n个元素。当数组经过resize扩容后,新分配的数组中除了前self.n个被复制的元素外,剩余位置都是未初始化的ctypes.py_object(对应C层面的NULL指针)。Python尝试将这些NULL指针转换为PyObject时,就会抛出ValueError: PyObject is NULL。

错误偶发是因为Python对ctypes数组的遍历行为可能存在优化,某些情况下未被初始化的位置可能没被实际访问到,但这是不确定的,所以报错不是每次都出现。

修复方案

修改get_array方法,只取数组中前self.n个已初始化的元素:

def get_array(self):
    return list(self.array[:self.n])

这样转换list时只会遍历已添加的有效元素,不会触及那些未初始化的NULL位置,彻底避免报错。

内容的提问来源于stack exchange,提问作者Ahmed Fakhry

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 15:07:07