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

Python中__mul__与__rmul__调用规则及列表与numpy数组相乘异常问题

现象背后的核心逻辑

你遇到的反常表现是Python为数值计算生态预留的兼容设计导致的,核心涉及两个规则:标准二元运算符的调用流程、内置类型对numpy数组协议的特殊处理。


完整的二元运算符调用规则(以*为例)

官方文档描述的规则是简化版,完整执行流程如下:

  1. 执行a * b时优先调用a.__mul__(b)
    • 若方法存在且返回值不是NotImplemented,直接使用该返回值
    • 若方法不存在,或返回NotImplemented,进入下一步
  2. 校验右操作数类型:
    • 若b的类型是a类型的子类,直接判定运算不支持,抛出TypeError
    • 若不是子类,尝试调用b.__rmul__(a),若方法存在且不返回NotImplemented,使用该返回值
  3. 上述流程都失败则抛出TypeError

你测试的反常现象原因

1. 原生list和numpy标量相乘的表现

原生list的__mul__是C语言实现的内置方法,做了特殊兼容处理:通过运算符触发调用时,会先检测右操作数是否实现了numpy的数组通用函数协议__array_ufunc__,如果是就直接返回NotImplemented,把运算优先级让给numpy的实现。

  • 你用a * b触发运算时,list.__mul__检测到b是numpy标量,直接返回NotImplemented,Python转而调用b.__rmul__(a),把list转成numpy数组做数值乘法,得到[2 4 6]
  • 你手动显式调用a.__mul__(b)时,相当于直接调用list的乘法逻辑,跳过了协议检测的前置步骤,numpy的0维标量会被当成整数处理,所以返回重复两次的列表[1,2,3,1,2,3]

2. Foo1和Foo2的差异原因

  • Foo1继承自list,没有重写__mul__,用的还是C实现的原生内置方法,所以运算符触发时会走和原生list一样的协议检测逻辑,返回NotImplemented,调用numpy的__rmul__得到数组结果
  • Foo2重写了__mul__,是Python层面实现的方法,没有内置的协议检测逻辑,所以运算符触发时直接执行你实现的乘法逻辑,把numpy标量当整数处理,返回重复后的列表

这个设计不需要numpy修改内置类型的行为,是Python内置类型本身预留了对应兼容接口,方便第三方数值库实现自定义的运算逻辑。


内容的提问来源于stack exchange,提问作者z.ni

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 07:39:03