关于python:Slice表示法不在内存中创建新副本

Slice notation isn't creating a new copy in memory

我使用scipy和imread()将图像导入为rgb。假设我想分离出"r"组件并将其复制到内存中的一个新对象。以下代码有效:

1
2
3
4
5
6
7
8
9
10
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])

输出预期:

1
2
0
255

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

1
2
3
4
r = pic[:,:,0]
r[0,0] = 0
print(r[0,0])
print(pic[0,0,0])

输出:

1
2
0
0

公平地说,我从这里得到了语法提示,它涉及到使用类似于b = a[:]的片,而不是单个层。怎么样:

1
2
3
4
r = pic[:]
r[0,0,0] = 0
print(r[0,0,0])
print(pic[0,0,0])

或添加额外步骤:

1
2
3
4
5
r = pic[:]
r= r[:,:,0]
r[0,0] = 0
print(r[0,0])
print(pic[0,0,0])

静态输出:

1
2
0
0

它是一个数组而不是一个列表,但是这个数组的答案意味着这个语法应该是正常的。基本上,当我在示例中使用slice符号时,为什么一个新对象不是在内存中创建的?我想我遗漏了一些其他东西,我的谷歌搜索似乎告诉我语法应该有效。谢谢你的帮助!


您链接的另一个问题使用了不正确的术语;它询问的是关于python列表,而您使用的是一个numpy数组。对列表进行切片确实会为您提供所选范围的副本,但对数组进行切片会为您提供视图。对视图所做的更改将反映在原始视图中。

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