如何在python 3中有效地将原始字节写入numpy数组数据
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在python 3中有效地将原始字节写入numpy数组数据相关的知识,希望对你有一定的参考价值。
当将一些旧的python 2代码迁移到python 3时,我遇到了一些问题,即从字节对象填充结构化的numpy数组。
我有一个解析器,为我可能遇到的每种数据结构类型定义了一个特定的dtype。通常,由于给定的数据结构可能具有可变长度或可变类型的字段,因此这些字段已在numpy数组中表示为对象dtype(np.object #alternatively np.dtype('O')
)的字段。
首先通过填充fixed-dtype字段从字节(或bytearray
)获得数组。此后,可以使用前面的固定字段中的信息来构建任何子数组(包含在“对象”字段中)的dtype。
这里是在python 2中工作的此过程的一部分示例(仅处理fixed-dtype字段)。请注意,我们有一个名为'nSamples'
的字段,大概可以告诉我们所指向的数组的长度。数组的'samples'
字段,它将被解释为形状为(2,)
和dtype sampleDtype
的numpy数组:
fancyDtype = np.dtype([('blah', '<u4'), ('bleh', 'S5'), ('nSamples', '<u8'), ('samples', 'O')]) sampleDtype = np.dtype([('sampleId', '<u2'), ('val', '<f4')]) bytesFromFile = bytearray( b'*x00x00x00hellox02x00x00x00x00x00x00x00xd0xb5' b'x14_xa1x7fx00x00"x00x00x00x80?]x00x00x00xa0@') arr = np.zeros((1,), dtype=fancyDtype) numBytesFixedPortion = 17 # Start out by just reading the fixed-type portion of the array arr.data[:numBytesFixedPortion] = bytesFromFile[:numBytesFixedPortion] memoryview(arr.data)[:numBytesFixedPortion] = bytesFromFile[:numBytesFixedPortion]
这里的最后两个语句都在python 2.7中起作用。
值得注意的是,如果我键入
arr.data
我得到
<read-write buffer for 0x7f7a93bb7080, size 25, offset 0 at 0x7f7a9339cf70>
,它告诉我这是一个缓冲区。显然,memoryview(arr.data)
返回一个memoryview
对象。
这两个语句在python 3.6中都引发以下异常:
NotImplementedError: memoryview: unsupported format T{I:blah:5s:bleh:=Q:nSamples:O:samples:}
这告诉我numpy返回的访问类型是
data
,而不是memoryview
。它还告诉我buffer
在python 2.7中有效,但在python 3.6中不适用。
[我在numpy的问题跟踪器中发现了类似的问题:memoryviews
但是,该问题已迅速关闭,numpy开发人员指出这是https://github.com/numpy/numpy/issues/13617中的错误。由于ctypes
是内置函数,因此我对仅对其进行更新以得到修复的希望就放弃了。
我终于偶然发现了一个可行的解决方案,尽管它花费的时间大约是python 2.7方法的两倍。它是:
ctypes
一位同事还建议尝试使用此解决方案:
import struct struct.pack_into( 'B' * numBytesFixedPortion, # fmt arr.data, # buffer 0, # offset *buf[:numBytesFixedPortion] # unpacked byte values )
但是,在执行此操作时,我得到了例外:
arrView = arr.view('u1') arrView[:numBytesFixedPortion] = buf[:numBytesFixedPortion]
请注意,我在python 2.7和3.6中均收到此异常。似乎numpy不允许在具有任何
File "/home/tintedFrantic/anaconda2/envs/py3/lib/python3.6/site-packages/numpy/core/_internal.py", line 461, in _view_is_safe raise TypeError("Cannot change data-type for object array.") TypeError: Cannot change data-type for object array.
字段的阵列上进行查看。 (此外:通过注释掉numpy代码中对对象类型字段的检查,我能够使numpy正确地做到这一点,尽管这似乎是一种危险的解决方案(也不是一种非常可移植的解决方案)。)
我也尝试过创建单独的数组,一个数组具有fixed-dtype字段,另一个数组与object-dtype字段,然后使用object
合并它们。失败的原因是我不记得一条神秘的消息。
我有点茫然。我只想向numpy数组的基础内存写入一些任意字节,然后高效地进行操作。这似乎并不难,但是我还没有找到一种好的方法。我想要一个也不是hack的解决方案,因为这将进入需要高可靠性的系统。如果没有更好的方法,我将使用numpy.lib.recfunctions.merge_arrays
解决方案,但我希望那里的人知道更好的方法。顺便说一句,不使用object-dtype字段不是一个可行的选择,因为这样做的成本太高了。
[如果有问题,我正在python 2.7中使用numpy 1.16.2,对于python 3.6使用1.17.4。
当将一些旧的python 2代码迁移到python 3时,我遇到了一些问题,即从字节对象填充结构化的numpy数组。我有一个解析器,为每种类型的...定义一个特定的dtype ...
根据@nawsleahcimnoraa的建议,我发现在python 3.3+中(而不是在python 2.7中),在我的python 3环境中由struct.pack_into()
返回的memoryview
对象具有arr.data
方法。因此,我可以这样做
以上是关于如何在python 3中有效地将原始字节写入numpy数组数据的主要内容,如果未能解决你的问题,请参考以下文章
如何从 BluetoothChat 的输入/输出流中读取/写入原始十六进制字节?