为何列表中的numpy数组(skimage对象)在for循环迭代后未更新?
问题:循环修改列表中的numpy数组(skimage对象)不生效
先看问题中的示例代码:
import skimage as sk from skimage.util import img_as_ubyte, img_as_float import matplotlib.pyplot as plt import numpy as np a = np.random.randn(100,100,3).astype(np.uint8) b = np.random.randn(100,100,3).astype(np.uint8) a = img_as_float(a) l = [a , b] for ar in l: ar = img_as_float(ar) print(ar.dtype) for ar in l: print(ar.dtype)
执行输出:
float64 float64 float64 uint8
原因分析
问题本质是Python的变量引用机制导致的:
- 列表
l中存储的是原始numpy数组对象的引用。 - 在
for ar in l循环里,ar是临时变量,初始指向列表对应位置的数组对象。 - 执行
ar = img_as_float(ar)时,并没有修改原数组对象,只是将ar重新绑定到了img_as_float返回的新数组对象上。原列表中的元素依然指向旧数组,所以循环结束后列表内容无变化。
解决办法
方法1:列表推导式生成新列表
直接遍历原列表,将每个元素处理后生成新列表替换原列表,这是Python批量处理序列的常用简洁方式:
import skimage as sk from skimage.util import img_as_ubyte, img_as_float import numpy as np a = np.random.randn(100,100,3).astype(np.uint8) b = np.random.randn(100,100,3).astype(np.uint8) a = img_as_float(a) l = [a , b] # 批量处理生成新列表 l = [img_as_float(ar) for ar in l] # 验证结果 for ar in l: print(ar.dtype)
执行后会输出两个float64,符合预期。
方法2:通过索引修改列表元素
如果需要保留原列表的引用(比如其他代码还在使用这个列表变量),可以通过索引遍历,直接替换列表对应位置的元素:
for i in range(len(l)): l[i] = img_as_float(l[i])
这种方式直接操作列表的索引位置,将处理后的新数组赋值到对应位置,原列表内容会被直接更新。
补充说明
img_as_float函数会返回新数组对象(因为uint8到float64的类型转换无法在原数组内存中完成,两者字节长度不同),所以无法做到“原地修改”原数组。上述两种方法都是通过替换列表中的元素引用来实现批量更新的。
内容的提问来源于stack exchange,提问作者fenixnano
相关产品推荐
相关产品推荐

