Arrays 为什么deepcopy会更改numpy数组的值?

Arrays 为什么deepcopy会更改numpy数组的值?,arrays,numpy,scipy,copy,ode,Arrays,Numpy,Scipy,Copy,Ode,我遇到了一个问题,在使用copy.deepcopy或Numpy.copy复制Numpy数组后,Numpy数组中的值会发生变化。事实上,如果我只是在复制数组之前先打印它,我会得到不同的值 我使用的是Python 3.5、Numpy 1.11.1和Scipy 0.18.0 我的起始数组包含在元组列表中;每个元组都是成对的:一个浮点(一个时间点)和一个numpy数组(该时间点的ODE解决方案),例如: 在本例中,我需要最后一个时间点的数组 当我调用以下命令时: tandy = c1.Integrate

我遇到了一个问题,在使用copy.deepcopy或Numpy.copy复制Numpy数组后,Numpy数组中的值会发生变化。事实上,如果我只是在复制数组之前先打印它,我会得到不同的值

我使用的是Python 3.5、Numpy 1.11.1和Scipy 0.18.0

我的起始数组包含在元组列表中;每个元组都是成对的:一个浮点(一个时间点)和一个numpy数组(该时间点的ODE解决方案),例如:

在本例中,我需要最后一个时间点的数组

当我调用以下命令时:

tandy = c1.IntegrateColony(3)
ylast = copy.deepcopy(tandy[-1][1])
print(ylast)
tandy = c1.IntegrateColony(3)
print(tandy[-1][1])
ylast = copy.deepcopy(tandy[-1][1])
print(ylast)
我得到了一些对我试图模拟的系统有意义的东西:

[7.14923891e-07   7.14923891e-07 ... 8.26478813e-01   8.85589634e-01]
但是,在以下情况下:

tandy = c1.IntegrateColony(3)
ylast = copy.deepcopy(tandy[-1][1])
print(ylast)
tandy = c1.IntegrateColony(3)
print(tandy[-1][1])
ylast = copy.deepcopy(tandy[-1][1])
print(ylast)
我得到全零:

[0.00000000e+00   0.00000000e+00 ... 0.00000000e+00   0.00000000e+00]
[ 0.  0.  ...  0.  0.]

我应该补充一点,使用更大的系统和不同的参数,显示tandy[k][1](使用print()或仅通过在命令行中调用它)显示所有非常接近零的非零值,即发生这种情况的详细信息与
integrate
中如何处理
ytcurrent
有关。但是Python中有各种各样的上下文,其中列表的所有值最终都是相同的——这与预期相反

例如:

In [159]: x
Out[159]: [0, 1, 2]
In [160]: x=[]
In [161]: y=np.array([1,2,3])
In [162]: for i in range(3):
     ...:     y += i
     ...:     x.append(y)
In [163]: x
Out[163]: [array([4, 5, 6]), array([4, 5, 6]), array([4, 5, 6])]
x
的所有元素都具有相同的值-因为它们都是指向相同
y
的指针,因此显示其最终值

但是如果在将其添加到列表之前复制
y
,我会看到更改

In [164]: x=[]
In [165]: for i in range(3):
     ...:     y += i
     ...:     x.append(y.copy())
In [166]: x
Out[166]: [array([4, 5, 6]), array([5, 6, 7]), array([7, 8, 9])]
In [167]: 

这并不能解释为什么
print
语句会更改值。但整个
solout
回调机制有点模糊。我想知道在
scipy
中是否有关于定义这样一个回调的陷阱的警告?

如果您打印所有的sol,行是否会改变,或者是否都一样?您可能必须使用
sol.append((tcurrent,ytcurrent.copy())
,以避免始终存储指向积分器状态向量的相同指针。当您知道对象是数组时,不必麻烦使用
deepcopy
<代码>x。复制()就足够了。但我觉得坦迪有点滑稽。它不仅仅是一个独立值的列表。当你连续两次打印(tandy[-1][1])时会发生什么?我会试试看,LutzL。谢谢你,LutzL和hpaulj,谢谢你的建议!至少在一些快速测试中,LutzL建议在添加到sol时使用
ytcurrent.copy()
,这似乎修复了奇怪的行为。但是,我想知道为什么只调用
tandy
print(tandy)
vs
copy.deepcopy(tandy)
numpy.copy(tandy)
会影响它所指向的值。谢谢hpaulj。我找不到任何关于
solout
陷阱的讨论。你描述的案例很熟悉(尽管我仍然经常被它绊倒!),但似乎无法解释我看到的行为。另外,只需调用
tandy[-1][1]
(例如,在控制台中)与
numpy.copy()
)不同
copy.deepcopy(somearray)
numpy.copy(somearray)
都调用numpy的
array(somearray)
,但我无法进一步跟踪numpy迷宫。。。也许
array(somearray)
以另一种方式调用值?如果您给我们一个完整的复制粘贴示例,我可以自己运行它并检查
tandy
对象。我也会尝试一些变体,比如只存储当前值的变体,或者在每次迭代时打印一个值的变体。感谢您查看。在每个
solout
调用中,
ytcurrent
都有一个新的
id
,但它共享数据缓冲区(以及
yfinal
)。它们都是同一事物的视图。因此,如果您希望每次迭代都使用
ytcurrent
值(而不仅仅是最后一次迭代),则必须使用
copy
in
solout
。我还没有弄清楚为什么“未受保护”的打印会重置这些值。我已经得出结论,这种重置是由内部numpy错误引起的;这与代码中的误用无关。我想我们可以搜索或提交错误报告。但无论它是否已修复,在
solout
中的
copy()
都是正确的用法。
[(0.0, array([ 0.,  ...  0.])), ...
 (3.0, array([ 0.,  ...  0.]))]
tandy = c1.IntegrateColony(3); ylast=copy.deepcopy(tandy)
[7.14923891e-07   7.14923891e-07 ... 8.26478813e-01   8.85589634e-01]
import numpy as np
from scipy.integrate import ode


def testODEint(tmax=1):
    C0 = np.ones((3,))
    # C0 = 1  # This seems to behave the same

    def dCdt_simpleinputs(t, C):
        return C

    y = ode(dCdt_simpleinputs)

    y.set_integrator('dopri5')
    sol = []

    def solout(tcurrent, ytcurrent):
        sol.append((tcurrent, ytcurrent))  # Behaves oddly
        # sol.append((tcurrent, ytcurrent.copy()))  # LutzL's idea: Works

    y.set_solout(solout)
    y.set_initial_value(y=C0, t=0)
    yfinal = y.integrate(tmax)

    return sol

tandy = testODEint(1)
ylast = np.copy(tandy[-1][1])
print(ylast)  # Expect same values as tandy[-1][1] below

tandy = testODEint(1)
tandy[-1][1]
print(tandy[-1][1])  # Expect same values as ylast above
[ 2.71828196  2.71828196  2.71828196]
[  0.00000000e+00   0.00000000e+00   0.00000000e+00]
In [159]: x
Out[159]: [0, 1, 2]
In [160]: x=[]
In [161]: y=np.array([1,2,3])
In [162]: for i in range(3):
     ...:     y += i
     ...:     x.append(y)
In [163]: x
Out[163]: [array([4, 5, 6]), array([4, 5, 6]), array([4, 5, 6])]
In [164]: x=[]
In [165]: for i in range(3):
     ...:     y += i
     ...:     x.append(y.copy())
In [166]: x
Out[166]: [array([4, 5, 6]), array([5, 6, 7]), array([7, 8, 9])]
In [167]: