<p>您真正想要的阵列类型不清楚,目的也不清楚。但谈到连续(或连续)和缓存,表明您不清楚Python是如何工作的</p>
<p>首先,Python一直都是面向对象的。整数、字符串、列表都是某个类的对象,具有相关的方法和属性。对于内置类,我们对存储几乎没有发言权</p>
<p>让我们列出一个小清单:</p>
<pre><code>In [89]: alist = [1,2,3,1000,1001,1000,'foobar']
In [90]: alist
Out[90]: [1, 2, 3, 1000, 1001, 1000, 'foobar']
</code></pre>
<p>列表有一个数据缓冲区,用于存储指向内存中其他位置的对象的引用(如果愿意,可以使用指针)。<code>id</code>可能会给出一些关于where的概念,它不应该被理解为<code>c</code>语言意义上的“指针”</p>
<p>对于此列表:</p>
<pre><code>In [91]: [id(i) for i in alist]
Out[91]:
[9784896,
9784928,
9784960,
140300786887792,
140300786888080,
140300786887792,
140300786115632]
</code></pre>
<p>1,2,3的id值很小,因为Python在开始时初始化了小整数(最多256个)。因此,所有使用都将具有唯一的id</p>
<pre><code>In [92]: id(2)
Out[92]: 9784928
</code></pre>
<p>在列表创建中<code>1000</code>似乎是唯一的,但在该上下文之外并非如此</p>
<pre><code>In [93]: id(1001)
Out[93]: 140300786888592
</code></pre>
<p>看起来字符串也被缓存了——但这只是解释器的选择,我们不应该指望它</p>
<pre><code>In [94]: id('foobar')
Out[94]: 140300786115632
</code></pre>
<p>反向列表是一个新列表,具有自己的指针数组。但参考文献相同:</p>
<pre><code>In [95]: rlist = alist[::-1]
In [96]: rlist
Out[96]: ['foobar', 1000, 1001, 1000, 3, 2, 1]
In [97]: rlist[5],id(rlist[5])
Out[97]: (2, 9784928)
</code></pre>
<p>像<code>[::-1]</code>这样的索引操作应该只取决于列表中的项目数。它不取决于值实际指向的位置。其他副本也一样。即使是附加到数组中,也是相对独立于时间的(它在数据缓冲区中保持增长空间)。实际处理列表中的对象可能取决于它们存储在内存中的位置,但我们对此没有什么可说的</p>
<p>“2d”列表实际上是包含列表元素的列表;嵌套列表。子列表存储在内存中的其他位置,就像字符串和数字一样。从这个意义上说,嵌套列表是不连续的</p>
<p>那么阵列呢</p>
<pre><code>In [101]: x = np.arange(12)
In [102]: x
Out[102]: array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
In [104]: x.__array_interface__
Out[104]:
{'data': (57148880, False),
'strides': None, # default (8,)
'descr': [('', '<i8')],
'typestr': '<i8',
'shape': (12,),
'version': 3}
In [105]: x.nbytes # 12*8 bytes
Out[105]: 96
</code></pre>
<p><code>x</code>是一个<code>ndarray</code>对象,具有<code>shape</code>、<code>strides</code>和<code>dtype</code>等属性。和一个数据缓冲区。在本例中,是96字节长的<code>c</code>数组,在“57148880<code>. We can't use that number, but I find it useful when comparing this </code>数组接口<code>dict across arrays. A</code>视图`尤其具有相同或相关的值</p>
<pre><code>In [106]: x.reshape(3,4)
Out[106]:
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
In [107]: x.reshape(3,4).__array_interface__['data']
Out[107]: (57148880, False)
In [108]: x.reshape(3,4)[1,:].__array_interface__['data']
Out[108]: (57148912, False) # 32 bytes later
</code></pre>
<p>数组数据缓冲区具有实际值,而不是引用。这里使用<code>int</code>dtype,每个8字节被解释为一个“int64”值</p>
<p>你的<code>id</code>迭代有效地要求一个列表<code>[x[i] for i in range(n)]</code>。数组的元素必须是“未绑定的”,并且是一个新对象,类型为<code>np.int64</code>。虽然不是数组,但它确实有许多与1元素数组相同的属性</p>
<pre><code>In [110]: x[4].__array_interface__
Out[110]:
{'data': (57106480, False),
...
'shape': (),....}
</code></pre>
<p>该<code>data</code>值与<code>x</code>值无关</p>
<p>只要在现有数组上使用<code>numpy</code>方法,速度就很好,通常比同等的列表方法快10倍。但是如果从列表开始,则创建数组需要时间。而且像列表一样处理数组的速度很慢</p>
<p>而<code>x</code>的反面呢</p>
<pre><code>In [111]: x[::-1].__array_interface__
Out[111]:
{'data': (57148968, False),
'strides': (-8,),
'descr': [('', '<i8')],
'typestr': '<i8',
'shape': (12,),
'version': 3}
</code></pre>
<p>这是一个新的数组,但是有一个不同的<code>strides</code>(-8,),并且<code>data</code>指向缓冲区的末尾<code>880+96-8</code></p>