Python科学计算(第2版)
上QQ阅读APP看书,第一时间看更新

2.5.3 与结构数组共享内存

从结构数组获取某个字段时,得到的是原数组的视图,但是如果获取多个字段,将得到一个全新的数组,不与原数组共享内存。

    persontype = np.dtype({
        'names':['name', 'age', 'weight', 'height'],
        'formats':['S30','i', 'f', 'f']}, align= True )
    a = np.array([("Zhang", 32, 72.5, 167.0), 
                  ("Wang", 24, 65.2, 170.0)], dtype=persontype)
    
    print a["age"].base is a  #视图
    print a[["age", "height"]].base is None #复制
    True
    True

为了创建结构数组的多字段视图,可以使用下面的fields_view( )函数。它通过原数组的dtype属性创建视图数组的dtype对象。然后通过ndarray( )创建视图数组。

    def fields_view(arr, fields):
        dtype2 = np.dtype({name:arr.dtype.fields[name] for name in fields})
        return np.ndarray(arr.shape, dtype2, arr, 0, arr.strides)
    
    v = fields_view(a, ["age", "weight"])
    print v.base is a
    
    v["age"] += 10
    print a
    True
    [('Zhang', 42, 72.5, 167.0) ('Wang', 34, 65.19999694824219, 170.0)]

dtype对象的fields属性是一个以字段名为键、以字段类型和字节偏移量为值的字典,使用它创建新的dtype对象时,可以保持字段的偏移量:

    print a.dtype.fields
    print a.dtype
    print v.dtype
    {'age': (dtype('int32'), 32), 'name': (dtype('S30'), 0), 
    'weight': (dtype('float32'), 36), 'height': (dtype('float32'), 40)}
    {'names':['name','age','weight','height'], 'formats':['S30','<i4','<f4','<f4'], 
      'offsets':[0,32,36,40], 'itemsize':44, 'aligned':True}
   {'names':['age','weight'], 'formats':['<i4','<f4'], 'offsets':[32,36], 'itemsize':40}

如果这两个dtype对象的itemsize属性相同,那么可以使用数组的view( )方法创建视图对象。但是从上面的输出可以看到两个dtype对象的字节数并不相同,一个是44个字节,另一个是40个字节。遇到这种情况时,可以使用ndarray( )创建数组的视图,它的调用参数如下:

    ndarray(shape, dtype=float, buffer=None, offset=0, strides=None, order=None)

●shape:所创建数组的形状。

●dtype:数组元素类型的dtype对象。

●buffer:拥有buffer接口的对象,所创建的数组将与该对象共享内存。

●offset:buffer对象的数据内存中的起始地址的偏移量。

●strides:所创建数组的strides属性,即每个轴上的下标增加1时的地址增量。

●order:C语言格式或Fortran语言格式。

在fields_view( )中,我们所创建的数组视图与原数组拥有相同的shape、data和strides属性。而dtype属性中的字段与原数组拥有相同的偏移量,显然这样的新数组能够与原数组共享内存。