为何numpy.ndarray.view会忽略之前的numpy.ndarray.newbyteorder调用?
newbyteorder后用view看字节没变化? 这问题问得特别精准,刚好踩中了NumPy字节序处理里最容易混淆的点——newbyteorder和byteswap的本质完全不一样,而view的逻辑也和你想的有点区别,咱一步步掰扯清楚:
先搞懂newbyteorder到底在干啥
你要记住:newbyteorder根本不会碰内存里的实际字节,它只是修改了数组dtype的「字节序标记」——相当于告诉NumPy:“下次你解析这块内存里的数据时,别用原来的字节序了,按我指定的来读”。
拿你的例子说:
- 你的平台是小端序,数组
a的内存里实际存的字节是[21, 205, 91, 7](这是123456789按小端序拆分的结果)。 - 当你执行
a.newbyteorder(">"),只是把dtype从=u4(本地小端)改成了>u4(大端),内存里的字节还是[21,205,91,7]没动。 - 这时候数组显示的数值变成365779719,是因为NumPy用大端序去解析那四个字节了:
21*2^24 + 205*2^16 + 91*2^8 +7,算出来就是这个数——但字节本身没换位置。
再看view的逻辑:直接读内存原始字节
view的核心是绕过dtype的字节序标记,直接把内存里的原始字节当成新的dtype来解读。不管你之前用newbyteorder改了什么“解析规则”,view(np.uint8)就是把内存里的每个字节单独拎出来,所以不管你是<还是>的dtype标记,结果都是那四个原始字节[21,205,91,7]。
这就是你困惑的根源:你以为view会跟着newbyteorder的解析规则走,但实际上它完全不关心dtype的字节序,只认内存里的真实字节。
对比byteswap:真·修改字节顺序
byteswap就不一样了,它是实实在在地调换内存里的字节位置(默认返回一个副本,加inplace=True会直接修改原数组)。比如a.byteswap(">")会把内存里的[21,205,91,7]改成[7,91,205,21],这时候用view(np.uint8)看,自然就是调换后的字节,数值也会跟着变——因为字节真的动了。
不想复制数据,怎么看指定字节序的字节?
如果你不想复制数据,又想看到按大端序排列的字节视图,可以直接对uint8的视图做反向切片:
a.view(np.uint8)[::-1] # 输出 array([7, 91, 205, 21], dtype=uint8)
这是一个反向的视图,不会复制原数据,只是换了个读取顺序,和byteswap后的view结果一致,但原数组的内存字节完全没动。
内容的提问来源于stack exchange,提问作者finefoot

