如何在Python中分配数组大小

2024-04-25 20:18:08 发布

您现在位置:Python中文网/ 问答频道 /正文

Python新手来了。我已经找了很多办法来解决这个问题,但没有什么能完全满足我的需要。我想在程序开始时分配一个空数组,它有a行和b列。我想出了一个解决办法,但遇到了一个出乎意料的有趣问题。以下是我所拥有的:

a = 7
b = 5
array_ab = [['?'] * b] * a

产生

[['?', '?', '?', '?', '?'],
 ['?', '?', '?', '?', '?'],
 ['?', '?', '?', '?', '?'],
 ['?', '?', '?', '?', '?'],
 ['?', '?', '?', '?', '?'],
 ['?', '?', '?', '?', '?'],
 ['?', '?', '?', '?', '?']]

但是,如果我试图更改单个元素,它会将每一行视为同一个对象,并有效地将整个列更改为该元素。例如

array_ab[4][2] = '1'

产生

[['?', '?', '1', '?', '?'],
 ['?', '?', '1', '?', '?'],
 ['?', '?', '1', '?', '?'],
 ['?', '?', '1', '?', '?'],
 ['?', '?', '1', '?', '?'],
 ['?', '?', '1', '?', '?'],
 ['?', '?', '1', '?', '?']]
显然,我需要一个更好的方法来创建空白数组,而不是乘法。在python中有解决这个问题的方法吗?(在FORTRAN中很简单!)


Tags: 对象方法程序元素ab数组array空白
3条回答

如果要使用数组进行数值计算,并且可以导入外部库,那么我建议查看numpy。 它提供了一个数组类和许多有用的数组操作。

创建MxN数组很简单

import numpy as np

A = np.empty((M,N)) # Empty array
B = np.zeros((M,N)) # Array filled with zeros

然后像这样进行索引

x = A[i,j]
A[4,2] = 1

row1 = A[0, :] # or simply A[0]

问题就在这里:

array_ab = [['?'] * 4] * 3

这个问题是由python选择通过对象引用传递列表造成的。因为列表是可变对象。

但是由于列表可能会变得非常大,而不是在内存中移动整个列表,所以Python选择只使用引用(C术语中的“指针”)。如果将一个指定给另一个变量,则只指定对它的引用。这意味着您可以让两个变量指向内存中的同一列表:

>>> a = [1]
>>> b = a
>>> a[0] = 2
>>> print b
[2]

因此,在您的第一行代码中有['?'] * 4

现在['?']是指向内存中的值?的指针,当您对其进行乘法运算时,会得到指向内存中相同位置的指针。

但是,当您更改其中一个值时,Python知道指针需要更改以指向新值:

>>> a = 4 * ['?']
>>> a
['?', '?', '?', '?']]

您可以验证列表中元素的id:

>>> [id(v) for v in a]
[33302480, 33302480, 33302480, 33302480]
>>> a[0] = 1
>>> a
[1, '?', '?', '?']

当你把这个列表相乘时,问题就来了——你得到了列表指针的四个副本。 现在,当您更改一个列表中的一个值时,这四个值将一起更改。

建议的方法是先创建一个所需长度的列表,然后用新创建的列表填充每个元素:

>>> A = [None] * 3
>>> for i in range(3):
...     A[i] = [None] * 4
...
>>> A
[[None, None, None, None], [None, None, None, None], [None, None, None, None]]
>>>

这将生成一个包含3个长度为4的不同列表的列表。

或者您可以使用列表理解:

w, h = 4, 3
A = [[None] * w for i in range(h)]
[[None, None, None, None], [None, None, None, None], [None, None, None, None]]

编辑2

根据标题,在“高级”中无法为列表分配准确的内存。Python list正在使用某种算法来过度分配列表大小,以便将来进行额外的增长。

from the source code:

 /* This over-allocates proportional to the list size, making room
 * for additional growth.  The over-allocation is mild, but is
 * enough to give linear-time amortized behavior over a long
 * sequence of appends() in the presence of a poorly-performing
 * system realloc().
 * The growth pattern is:  0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
 */

有点像

In [12]: a = 5

In [13]: b = 7

In [14]: array_ab = [ [ '?' for i in xrange(a) ] for j in xrange(b) ]

In [15]: array_ab
Out[15]:
[['?', '?', '?', '?', '?'],
 ['?', '?', '?', '?', '?'],
 ['?', '?', '?', '?', '?'],
 ['?', '?', '?', '?', '?'],
 ['?', '?', '?', '?', '?'],
 ['?', '?', '?', '?', '?'],
 ['?', '?', '?', '?', '?']]

In [16]: array_ab[4][2] = '1'

In [17]: array_ab
Out[17]:
[['?', '?', '?', '?', '?'],
 ['?', '?', '?', '?', '?'],
 ['?', '?', '?', '?', '?'],
 ['?', '?', '?', '?', '?'],
 ['?', '?', '1', '?', '?'],
 ['?', '?', '?', '?', '?'],
 ['?', '?', '?', '?', '?']]

尤其是,您使用的是list comprehensionsxrange

相关问题 更多 >