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

SciPy稀疏矩阵传参执行+=未修改原对象原因解析

SciPy稀疏矩阵与NumPy数组执行+=操作时的原对象修改行为差异

问题现象

使用SciPy与NumPy进行开发时可以观察到如下不一致行为:

  • 定义内部仅执行m += m操作的函数func
  • 分别向函数传入2阶单位稀疏矩阵a = sparse.identity(2)、NumPy数组b = np.array([1, 2])
  • 调用func后,全局作用域下的稀疏矩阵a未发生任何修改,NumPy数组b却被修改为原值的2倍

复现代码

from scipy import sparse
import numpy as np

def func(m):
    m += m

a = sparse.identity(2)
b = np.array([1, 2])

print(a.todense()) # [[1,0],[0,1]]
func(a)
print(a.todense()) # 仍为[[1,0],[0,1]],无修改

print(b) # [1, 2]
func(b)
print(b) # 变为[2, 4],原对象被修改

差异产生的核心原因

该差异和Python函数传参机制无关——Python对所有对象统一采用传对象引用的规则,形参和实参初始时会指向同一个内存对象。行为不一致的根源是两类对象对原地自增运算符+=的底层实现逻辑完全不同:

  • NumPy ndarray的+=是严格的原地操作:运算时直接在原数组的内存空间上修改元素值,全程不会生成新的数组对象。因此函数内对形参m的修改会直接作用在全局变量b指向的同一块内存上,最终表现为原对象被修改。
  • SciPy绝大多数格式的稀疏矩阵(本例中sparse.identity默认返回CSR格式稀疏矩阵)没有为+=实现真正的原地修改逻辑:执行m += m时,底层会先计算m + m的结果生成一个全新的稀疏矩阵对象,再将局部变量m重新绑定到这个新对象上。整个过程中全局变量a始终指向最初的稀疏矩阵对象,没有任何修改操作作用到它身上,因此值不会发生变化。

可以通过id()函数快速验证该逻辑:在func函数内m += m语句的前后分别打印id(m),传入NumPy数组时两次输出的id完全一致,说明是同一个对象;传入稀疏矩阵时两次id不同,说明局部变量已经指向了新生成的对象。

如果需要对稀疏矩阵实现类似NumPy数组的原地修改效果,可以直接操作稀疏矩阵存储非零值的属性,避免生成新对象:

def sparse_inplace_add(m):
    # 对CSR/CSC等基于data属性存储非零值的稀疏格式有效
    m.data += m.data

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 05:30:47