切片表示法不会在内存中创建新副本

Posted

技术标签:

【中文标题】切片表示法不会在内存中创建新副本【英文标题】:Slice notation isn't creating a new copy in memory 【发布时间】:2018-04-05 18:20:09 【问题描述】:

我使用 scipy 和 imread() 将图像导入为 RGB。假设我想分离出“R”组件并将其复制到内存中的新对象。下面的代码有效:

import scipy as sp
import scipy.misc as misc
import matplotlib.pyplot as plt
%matplotlib inline 
pic = misc.imread("ARBITRARY IMAGE.png");

r = pic[:,:,0].copy()
r[0,0] = 0
print(r[0,0])
print(pic[0,0,0])

输出预期:

0
255

但是我通过以下路径到达那里,我不知道为什么它们不起作用:

r = pic[:,:,0]
r[0,0] = 0
print(r[0,0])
print(pic[0,0,0])

输出:

0
0

很公平,我从here 中获得了语法提示,它涉及使用像b = a[:] 这样的切片而不是单层。怎么样:

r = pic[:]
r[0,0,0] = 0
print(r[0,0,0])
print(pic[0,0,0])

或添加一个额外的步骤:

r = pic[:]
r= r[:,:,0]
r[0,0] = 0
print(r[0,0])
print(pic[0,0,0])

仍然输出:

0
0

它是一个数组而不是一个列表,但数组的this answer 暗示这种语法应该没问题。基本上,当我在示例中使用切片符号时,为什么没有在内存中创建新对象?我假设我错过了其他东西,我的谷歌搜索似乎告诉我语法应该有效。感谢您的帮助!

【问题讨论】:

变量pic 可能不是一个普通的数组,而是一些带有重载切片运算符的对象,它不会创建副本,而是引用相同数据的视图。例如。如果我没记错的话,numpy 也不喜欢创建副本。 【参考方案1】:

other question you linked 使用了不正确的术语;它询问的是 Python lists,而您使用的是 Numpy 数组。切片列表确实会为您提供所选范围的副本,但 slicing an array gives you a view 会改为。您对视图所做的更改会反映在原始视图中。

使用 Numpy 数组,您需要使用 copy() 来获得一个单独的副本,您可以在不影响原始数据的情况下对其进行更改。这是一种设计选择,因为 Numpy 数组通常非常大,您不想无意中复制它们。

【讨论】:

警告如果您使用的是 32 位 python np.array.copy 可能是一个昂贵的内存操作(numpy 需要连续内存) @David Duh 我什至没想到他们使用了错误的术语。乔然,我在这里不是必须的,但是你有其他选择吗?或者我应该尽量避免使用这样的数组进行复制

以上是关于切片表示法不会在内存中创建新副本的主要内容,如果未能解决你的问题,请参考以下文章

在 pentaho 的 CDE 仪表板的表组件中创建新列,表示 2 列的总和

python 在Python 3.4中创建新的Enum类(向后移植为'enum34')具有可打印的表示

没有副本的Python切片? [复制]

在 C++ 中创建新的数据类型

如何在 Unity 中创建数组的独立副本?

Core Data 自动迁移不会在我的新模型中创建新实体