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

NumPy标量与自定义序列、继承自列表的自定义类相乘表现差异的原因探究

NumPy标量与自定义序列、继承自列表的自定义类相乘表现差异的原因探究

这个问题的核心在于Python运算符重载的执行顺序,以及NumPy对不同类型对象的处理逻辑差异,我来给你拆解清楚:

首先,当你执行c * s这种乘法操作时,Python会遵循这样的流程:

  1. 先尝试调用左边对象(这里是numpy.float64标量)的__mul__方法,看它能不能处理右边的对象;
  2. 如果左边的__mul__返回NotImplemented(表示它搞不定),才会转而调用右边对象的__rmul__方法,把乘法的控制权交给右边的对象。

接下来看两种情况的具体差异:

1. 自定义序列类(不继承list)

你的第一个S类完全是自定义的,只实现了__len__和__getitem__来模拟序列行为,没有继承任何Python内置序列类型,所以它没有默认的__rmul__方法。

当NumPy标量的__mul__方法遇到这个对象时,会判断它是一个可迭代的自定义序列(通过__len__和__getitem__识别),于是自动把它转换成NumPy数组,然后执行标量与数组的逐元素乘法,最终返回结果数组,这就是你得到array([3., 6., 9.])的原因。

2. 继承自list的自定义类

第二个S类继承了list,这意味着它继承了list的所有内置方法,包括__rmul__。

NumPy在处理与Python内置类型(及其子类)的交互时,会优先尊重内置类型的运算符逻辑。当它看到右边是list的子类时,会让__mul__返回NotImplemented,把控制权交给右边对象的__rmul__方法。而list的__rmul__方法的逻辑是重复序列(比如[1,2] * 3会生成[1,2,1,2,1,2]),但它只接受整数作为乘数。你的c是numpy.float64类型的3.0,不是整数,自然就触发了错误:can't multiply sequence by non-int of type 'numpy.float64'。

如果你想让继承自list的类也支持这种乘法

可以重写__rmul__方法,手动实现和NumPy标量的交互逻辑,比如:

import numpy as np

class S(list):
    def __init__(self, lst):
        super().__init__(lst)  # 这里要用super初始化父类list,不然继承的list实例是空的

    def __rmul__(self, scalar):
        # 把自身转换成NumPy数组后再和标量相乘
        return np.array(self) * scalar

c = np.arange(3.0).sum()
s = S([1, 2, 3])
print(c * s)  # 输出:[3. 6. 9.]

备注:内容来源于stack exchange,提问作者Pavlo Bilous

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.16 09:48:08