NumPy ndarray子类__array_wrap__运行结果与文档示例不一致
NumPy子类化示例输出与文档不符问题说明
这一现象是官方文档内容过时导致的,既不是NumPy版本bug,也不是你对方法的使用理解有遗漏。
核心原因
NumPy在1.17版本对ufunc的类型分派逻辑做了不兼容旧流程的调整,而1.23版本文档中该章节的示例输出没有同步更新,仍然沿用了1.16及更早版本的执行流程结果。
1.16及更早版本的执行流程(对应文档给出的预期输出)
- 创建
MySubClass实例时,np.asarray(...).view(cls)触发第一次__array_finalize__:self是新创建的子类实例,obj是原始普通ndarray,对应输出第一组打印。 - ufunc
np.add执行计算时,先输出普通ndarray类型的计算结果,再调用子类的__array_wrap__方法,此时传入的out_arr是普通ndarray,对应文档中arr is array([1, 3, 5, 7, 9])的打印。 - 父类
__array_wrap__将普通ndarray结果转为子类实例时,触发第二次__array_finalize__:self是结果子类实例,obj是输入的子类实例,对应文档第三组打印。
1.17及之后版本的执行流程(对应你实际运行的输出)
- 版本更新后新增
__array_ufunc__作为ufunc分派的优先逻辑,基类默认实现会在ufunc计算开始前就提前将输出数组分配为对应子类类型,不再等计算完成后通过__array_wrap__做类型转换。 - 创建子类实例触发的第一次
__array_finalize__和旧版本完全一致。 - ufunc准备输出数组阶段,为输出数组分配子类类型时触发第二次
__array_finalize__:此时self是刚分配的输出子类实例(初始值和输入子类一致),obj是输入的子类实例,对应你运行结果中多出来的第二组打印。 - ufunc计算完成后调用
__array_wrap__时,传入的out_arr已经是提前分配好的子类实例,因此打印中arr显示为MySubClass类型。 - 由于输出数组已经是子类类型,父类
__array_wrap__不需要再做类型转换,也就不会触发旧流程中的第三次__array_finalize__。
补充说明
__array_wrap__目前仅作为兼容旧代码的接口保留,当前NumPy推荐子类自定义ufunc、函数行为时优先使用__array_ufunc__、__array_function__协议实现。
内容的提问来源于stack exchange,提问作者Wood
相关产品推荐
相关产品推荐

