在元组赋值 (Python) 中使用切片 Numpy 数组的机制是什么?
What is mechanism of using sliced Numpy arrays in a tuple assignment (Python)?
我知道Python中的元组赋值如下
a, b = b, a
的工作原理是先将b
和a
打包成一个元组(b, a)
,然后解包为a
和b
,从而实现交换一个声明中的两个名字。但是我发现如果 a
和 b
被切片的 Numpy 数组替换:
# intended to swap the two halves of a Numpy array
>>> import numpy as np
>>> a = np.random.randn(4)
>>> a
array([-0.58566624, 1.42857044, 0.53284964, -0.67801528])
>>> a[:2], a[2:] = a[2:], a[:2]
>>> a
array([ 0.53284964, -0.67801528, 0.53284964, -0.67801528])
我的猜测是压缩元组 (a[2:], a[:2])
实际上是指向 a[2]
和 a[0]
内存位置的“指针”元组。解包时,首先 a[:2]
被从内存 a[2]
开始的值覆盖。然后 a[2:]
被从 a[0]
开始的值覆盖。这是对机制的正确理解吗?
所以,这不是简单的作业。名称-对象绑定语义适用于简单赋值,即 a = b
.
如果你这样做:
a[ix] = b
然后确切的行为被推迟到类型,即它等同于
type(a).__setitem__(a, ix, b)
Numpy 数组基本上是原始的类 C 数组的面向对象包装器,实现了“真正的”多维数组接口。在这种情况下,要理解的关键是不同的 numpy 数组对象可以共享底层缓冲区。简单切片总是创建一个 numpy.ndarray 对象,它是原始数组的 view。
所以在这种情况下,上面的b
实际上是对nd.array.__getitem__
的调用。其中returns一个视图.
因此,考虑 Python 列表的简单情况。右边:
(a[2:], a[:2])
创建一个包含两个的元组,独立 列表对象(尽管是浅复制)。
当它们被分配到左侧的分配目标序列时,突变没有任何共享效果。三个列表对象有三个独立的缓冲区(列表对象不会创建视图)。
另一方面,表达式 a[2:], a[:2]
创建一个元组,其结果是切片原始 nd.array 对象的结果,由 nd.array.__getitem__
控制。这将创建两个新的数组对象,但它们在原始数组的基础缓冲区上 views。基本上,您在三个不同的数组对象之间共享相同的底层可变原始缓冲区。
我知道Python中的元组赋值如下
a, b = b, a
的工作原理是先将b
和a
打包成一个元组(b, a)
,然后解包为a
和b
,从而实现交换一个声明中的两个名字。但是我发现如果 a
和 b
被切片的 Numpy 数组替换:
# intended to swap the two halves of a Numpy array
>>> import numpy as np
>>> a = np.random.randn(4)
>>> a
array([-0.58566624, 1.42857044, 0.53284964, -0.67801528])
>>> a[:2], a[2:] = a[2:], a[:2]
>>> a
array([ 0.53284964, -0.67801528, 0.53284964, -0.67801528])
我的猜测是压缩元组 (a[2:], a[:2])
实际上是指向 a[2]
和 a[0]
内存位置的“指针”元组。解包时,首先 a[:2]
被从内存 a[2]
开始的值覆盖。然后 a[2:]
被从 a[0]
开始的值覆盖。这是对机制的正确理解吗?
所以,这不是简单的作业。名称-对象绑定语义适用于简单赋值,即 a = b
.
如果你这样做:
a[ix] = b
然后确切的行为被推迟到类型,即它等同于
type(a).__setitem__(a, ix, b)
Numpy 数组基本上是原始的类 C 数组的面向对象包装器,实现了“真正的”多维数组接口。在这种情况下,要理解的关键是不同的 numpy 数组对象可以共享底层缓冲区。简单切片总是创建一个 numpy.ndarray 对象,它是原始数组的 view。
所以在这种情况下,上面的b
实际上是对nd.array.__getitem__
的调用。其中returns一个视图.
因此,考虑 Python 列表的简单情况。右边:
(a[2:], a[:2])
创建一个包含两个的元组,独立 列表对象(尽管是浅复制)。
当它们被分配到左侧的分配目标序列时,突变没有任何共享效果。三个列表对象有三个独立的缓冲区(列表对象不会创建视图)。
另一方面,表达式 a[2:], a[:2]
创建一个元组,其结果是切片原始 nd.array 对象的结果,由 nd.array.__getitem__
控制。这将创建两个新的数组对象,但它们在原始数组的基础缓冲区上 views。基本上,您在三个不同的数组对象之间共享相同的底层可变原始缓冲区。