近日,在閱讀《Fluent Python》的第2.9.2節時,有一個關於記憶體視圖的例子,當時看的一知半解,後來查了一些資料,現在總結一下,以備後續查詢; 示例覆述 添加了一些額外的代碼,便於更好理解 我的理解和疑惑 是一個 類型的數組; 是使用上述數組創建的一個 "memoryview" ,即 記憶體 ...
近日,在閱讀《Fluent Python》的第2.9.2節時,有一個關於記憶體視圖的例子,當時看的一知半解,後來查了一些資料,現在總結一下,以備後續查詢;
示例覆述
添加了一些額外的代碼,便於更好理解
memoryview
>>> import array
>>> numbers = array.array('h', [-2, -1, 0, 1, 2])
>>> memv = memoryview(numbers)
>>> len(memv)
5
>>> memv[0]
-2
>>> memv_oct = memv.cast('B')
>>> memv_oct
<memory at 0x10869d7c8>
>>> memv_oct.tolist()
[254, 255, 255, 255, 0, 0, 1, 0, 2, 0]
>>> memv.tolist()
[-2, -1, 0, 1, 2]
>>> memv_oct[5] = 4
>>> numbers
array('h', [-2, -1, 1024, 1, 2])
>>> memv.tolist()
[-2, -1, 1024, 1, 2]
>>> memv_oct.tolist()
[254, 255, 255, 255, 0, 4, 1, 0, 2, 0]
我的理解和疑惑
nembers
是一個signed short int
類型的數組;memv
是使用上述數組創建的一個memoryview,即記憶體視圖,它使memv
能夠共用nembers
數組的記憶體,但不需要複製裡面的內容,這使得memv
也能夠訪問和操作numbers
數組的元素;memv[0] # -2
也就可以理解了。memv.cast('B')
把memv
轉換成一個unsigned char int
的新memoryview
,並返回給memv_oct
。memv_oct.tolist()
的元素比原始數組多了一倍:- signed short int在記憶體中是以2個位元組存儲,而
unsigned char int
在記憶體中則是1個位元組存儲。 memv.tolist()
和numbers
的內容還是一樣的,所以memoryview
只是換個角度看同一個事物,即所謂的橫看成嶺側成峰,遠近高低各不同- 至此,我有一個不理解的地方:為什麼
signed short int
類型的-2
轉換成unsigned char int
類型時,變成254 255
?
- signed short int在記憶體中是以2個位元組存儲,而
memv_oct[5] = 4
將signed short int
類型的0
的高位元組賦值成4
;在二進位的層面下看,即0000 0000 0000 0000
轉換成了0000 0000 0010 0000
,十進位也就是1024;- 同時,我們也可以看到
memv.tolist()
也隨著numbers
改變了。更能說明memoryview
只是對同一塊數據的進行不同形式的表達;
解惑
正整數的情況可以理解,負整數的情況就理解不了,這說明正負整數在記憶體中的存儲形式是不一樣的。有了方向我們就直接搜一下吧。
signed short int
類型的原碼最高位表示正負,0
代表正數,1
代表負數。- 它們記憶體中是以補碼的形式存儲的,其中正數的補碼和原碼相同;負數的補碼,是其原碼除符號位(即最高位)外,其餘全部取反,再加1;
signed short int
類型的-2
,其原碼為0100 0000 0000 0001
,除符號位取反,為1011 1111 1111 1111
,再加1,為0111 1111 1111 1111
。當以unsigned char int
類型讀出來的時候,就成了254 255
了;-1
亦是同理,即255 255
;
總結
其實這都是《電腦組成原理》的基本知識,只是當我們習慣了使用一些高級編程語言的時候,對於這些底層的東西就不那麼敏感了。