代码之家  ›  专栏  ›  技术社区  ›  Eric Auld

在python中,视图和浅拷贝有什么区别?

  •  1
  • Eric Auld  · 技术社区  · 7 年前

    在numpy中,我理解对数组进行切片会给您一个“视图”,在我看来,这与浅层副本完全相同。它们有什么不同?

    1 回复  |  直到 7 年前
        1
  •  2
  •   Ovaflo    7 年前

    与包含对第一级元素对象的引用的python list对象(反过来可能引用更深层的对象)不同,numpy数组只引用单个数据缓冲区,该缓冲区存储数组所有维度的所有元素值,并且没有层次结构F元素对象超出此数据缓冲区。

    列表的浅副本将包含第一级元素引用的副本,并与原始列表共享被引用的元素对象。一个numpy数组的浅拷贝应该包含什么并不明显。应该吗?( )与原始文件共享数据缓冲区,或( )有自己的副本(这实际上使它成为一个深度副本)?

    看法 numpy数组的一个浅拷贝在某种意义上是a,即它引用与原始数据相同的数据缓冲区,因此对原始数据的更改会影响视图数据,反之亦然。

    图书馆职能 复制。复制() 本应创建其参数的浅层副本,但当应用于numpy数组时,它将创建一个浅层副本(即,新数组获得自己的数据缓冲区副本),因此对一个数组的更改不会影响另一个数组。

    下面的代码展示了复制/查看numpy数组的不同方法:

    import numpy as np
    import copy
    
    x = np.array([10, 11, 12, 13])
    
    # Create views of x (shallow copies sharing data) in 2 different ways
    x_view1 = x.view()
    x_view2 = x[:]          # Creates a view using a slice
    
    # Create full copies of x (not sharing data) in 2 different ways
    x_copy1 = x.copy()
    x_copy2 = copy.copy(x)  # Calls x.__copy__() which creates a full copy of x
    
    # Change some array elements to see what happens
    x[0]       = 555        # Affects x, x_view1, and x_view2
    x_view1[1] = 666        # Affects x, x_view1, and x_view2
    x_view2[2] = 777        # Affects x, x_view1, and x_view2
    x_copy1[0] = 888        # Affects only x_copy1
    x_copy2[0] = 999        # Affects only x_copy2
    
    print(x)                # [555 666 777  13]
    print(x_view1)          # [555 666 777  13]
    print(x_view2)          # [555 666 777  13]
    print(x_copy1)          # [888  11  12  13]
    print(x_copy2)          # [999  11  12  13]
    

    上面的示例创建整个原始数组索引范围的视图,并使用与原始数组相同的数组属性,这不是很有趣(可以用简单的别名替换,例如x_alias=x)。使视图强大的是它们可以是所选视图 部分 具有不同的属性。这在下面几行代码中进行了演示,这些代码扩展了上述示例:

    x_view3 = x[::2].reshape(2,1) # Creates a reshaped view of every 2nd element of x
    print(x_view3)          # [[555]
                            #  [777]]
    x_view3[1] = 333        # Affects 2nd element of x_view3 and 3rd element of x
    print(x)                # [555 666 333  13]
    print(x_view3)          # [[555]
                            #  [333]]