c语言编程笔录

首页 >   > 笔记大全

笔记大全

numpy数组拷贝地址所引起的同步替换问题怎么解决

更新时间:2023-12-22

问题描述

在使用numpy数组的过程中,我们有时候需要对一个已有的数组进行拷贝(或者截取),然后对这个拷贝数组进行一系列的操作,然后再将其赋值给原数组,以此达到更新原数组的目的。但是,这样做会引起一个问题:如果对拷贝的数组进行了改动,原数组同时也会被改动,这样就会引起同步替换的问题。下面我们来具体解释一下。

import numpy as np

# 创建一个ndarray
a = np.array([1, 2, 3, 4, 5])

# 将ndarray进行切片操作,相当于对原数组进行了拷贝操作
b = a[:]

# 对拷贝数组进行改动
b[0] = 0

# 输出原数组的值
print(a) # 输出[0, 2, 3, 4, 5]

问题分析

以上的代码,我们首先创建了一个ndarray,然后对其进行切片操作,相当于生成了一个新的b数组,同时a数组和b数组是完全独立的,它们的物理存储空间不同。因此,当我们对b进行改动时(此处是将第一个元素赋值为0),a数组不会受到任何影响。但是,如果我们进行如下操作:

import numpy as np

# 创建一个ndarray
a = np.array([1, 2, 3, 4, 5])

# 将ndarray进行赋值操作,相当于对原数组进行了拷贝操作
b = a

# 对拷贝数组进行改动
b[0] = 0

# 输出原数组的值
print(a) # 输出[0, 2, 3, 4, 5]

这里我们对a数组进行了赋值操作,由于赋值操作只是对a数组进行了另一个变量名的赋值,并没有进行拷贝操作,所以b数组和a数组是共享存储空间的,它们指向同一块物理内存。因此,当我们对b进行改动(此处是将第一个元素赋值为0)时,实际上是对a数组进行了改动,导致原数组的值也被改动,这就是同步替换的问题。

问题解决

既然我们已经明确了同步替换问题的原因,那么我们也可以采取一些具体的方式来解决这个问题。

1. 使用ndarray的copy()函数或者deepcopy()函数进行数组的拷贝

使用ndarray的copy()函数或者deepcopy()函数可以创建一个完全独立的新数组,此时我们对新数组的任何修改都不会对原数组造成影响。

import numpy as np

# 创建一个ndarray
a = np.array([1, 2, 3, 4, 5])

# 将ndarray进行拷贝操作
b = a.copy()

# 对拷贝数组进行改动
b[0] = 0

# 输出原数组的值
print(a) # 输出[1, 2, 3, 4, 5]

2. 使用ndarray的view()函数进行数组的拷贝

使用ndarray的view()函数可以创建一个共享原数组数据的新数组,但是这个新数组的物理存储空间是独立的。这样我们就可以在原数组的基础上创建一个新数组,实现对原数组的拷贝,而且对新数组的任何修改都不会对原数组造成影响。

import numpy as np

# 创建一个ndarray
a = np.array([1, 2, 3, 4, 5])

# 将ndarray进行拷贝操作
b = a.view()

# 对拷贝数组进行改动
b[0] = 0

# 输出原数组的值
print(a) # 输出[0, 2, 3, 4, 5]

总结

在日常的代码编写过程中,如果我们使用的是numpy数组,那么在进行拷贝操作时,一定要注意是否会出现同步替换的问题。如果直接对数组进行赋值操作,那么赋值的新数组和原数组会共享存储空间,此时我们对新数组的修改会同时作用于原数组。如果需要对数组进行修改操作,那么我们可以使用copy()函数或者deepcopy()函数创建一个完全独立的新数组,或者使用view()函数在原数组的基础上创建一个共享数据但是独立存储的新数组,这样就可以避免同步替换问题的出现。