【问题标题】:In numpy, q1 = p[:] instead of q1 = p, yet p is modified when I modify q1? [duplicate]在numpy中,q1 = p[:]而不是q1 = p,但是当我修改q1时p被修改了? [复制]
【发布时间】:2020-03-26 13:23:43
【问题描述】:

我对在 Python 中复制 Numpy 数组的工作方式感到困惑。我从以下内容开始:

import numpy as np
p = np.array([1.0, 0.0, 1.0, 0.3])

然后我尝试使用以下三种方法制作 p 的“副本”:

q = p
q1 = p[:]
q2 = p.copy()

现在我执行q1[2] = 0.2,然后检查q、q1和q2的值。我惊讶地发现 p、q 和 q1 都变成了array([1.0, 0.0, 0.2, 0.3]),而只有 q2 保持不变。我还使用id()检查了所有四个变量(p、q、q1、q2)的地址,并确认id(p) = id(q),但id(q1) != id(p)

我的问题是,如果id(q1) != id(p),q1 的修改如何改变 p 和 q?谢谢!

【问题讨论】:

  • 2 个具有唯一 ID 的对象仍然可以访问共享内存
  • @byxor 感谢您的快速回复!那么这个ID指的是什么?我以为 id(x) 会检查 x 的内存位置,不是吗?
  • [...][:] 制作列表的(浅)副本,因为这是定义 list.__getitem__ 的方式。 np.array.__getitem__ 的定义不同。
  • @Xiao 正确。尽管没有什么可以阻止具有不同内存地址的 2 个对象修改 1 块共享内存。例如。如果一个类的 2 个实例包含对列表的引用,则这些实例将具有单独的 ID,但它们都将操作(列表的)相同的底层内存。
  • @byxor 我明白了。这很有帮助。谢谢!

标签: python numpy


【解决方案1】:

Numpy 状态的documentation

基本切片生成的所有数组都是原始数组的视图。

因此,在您的情况下,q1pview,反映了对 p 所做的更改。

【讨论】:

    【解决方案2】:

    因为您使用的是简单的切片操作,numpy 将使用数组结果切片的共享内存视图。在这种情况下,它是整个数组。它们被不同的 python 对象引用,但底层的 numpy 数组是相同的。 q1 只是 p 引用的同一数组的视图。

    您可以使用np.shared_memory 进行检查。

    import numpy as np
    p = np.array([1.0, 0.0, 1.0, 0.3])
    
    q1 = p[:]
    
    np.shares_memory(p, q1)
    # returns:
    True
    

    当切片不属于整个数组时也是如此。如:

    p = np.array([1.0, 0.0, 1.0, 0.3])
    
    q2 = p[1::2]
    print(q2)
    #prints:
    [0.  0.3]
    
    # setting a value of q2 changes p
    q2[0] = 10.0
    p
    # returns:
    array([ 1. , 10. ,  1. ,  0.3])
    

    【讨论】:

    • 感谢您的回复!那么为了创建一个真正独立的 p 副本,我应该使用 p.copy() 吗?
    • 是的。这是最好的方法。
    • 感谢您的回复!一个后续问题:就制作 p 的独立副本(这样对 q2 的更改不会影响 p)而言,q2 = p.copy() 是否足够?我是否需要 q2 = p.deepcopy() 来确保 q2 独立于 p?
    • 复制应该足够了,除非它是一个嵌套python对象的numpy数组。
    • 感谢您的回复!这对我很有帮助:)
    猜你喜欢
    • 2021-05-12
    • 2021-10-13
    • 2021-09-06
    • 1970-01-01
    • 2018-07-23
    • 1970-01-01
    • 1970-01-01
    • 2023-02-22
    • 1970-01-01
    相关资源
    最近更新 更多