Python標準庫---1四、內置類型:二進制序列類型 (memoryview)

上一篇文章: Python標準庫---1三、內置類型:二進制序列類型 ( bytes, bytearray)
下一篇文章: Python標準庫---1五、內置類型:集合類型、映射類型

內存視圖

memoryview 對象容許 Python 代碼訪問一個對象的內部數據,只要該對象支持 緩衝區協議 而無需進行拷貝。segmentfault

class memoryview(obj)

建立一個引用 obj 的 memoryview。 obj 必須支持緩衝區協議。 支持緩衝區協議的內置對象包括 bytes 和 bytearray。數組

memoryview 具備 元素 的概念,即由原始對象 obj 所處理的基本內存單元。 對於許多簡單類型例如 bytes 和 bytearray 來講,一個元素就是一個字節,可是其餘的類型例如 array.array 可能有更大的元素。ide

len(view) 與 tolist 的長度相等。 若是 view.ndim = 0,則其長度爲 1。 若是 view.ndim = 1,則其長度等於 view 中元素的數量。 對於更高的維度,其長度等於表示 view 的嵌套列表的長度。 itemsize 屬性可向你給出單個元素所佔的字節數。spa

memoryview 支持經過切片和索引訪問其元素。 一維切片的結果將是一個子視圖:3d

>>> v = memoryview(b'abcefg')
    >>> v[1]
    98
    >>> v[-1]
    103
    >>> v[1:4]
    <memory at 0x7f3ddc9f4350>
    >>> bytes(v[1:4])
    b'bce'

若是 format 是一個來自於 struct 模塊的原生格式說明符,則也支持使用整數或由整數構成的元組進行索引,並返回具備正確類型的單個 元素。 一維內存視圖可使用一個整數或由一個整數構成的元組進行索引。 多維內存視圖可使用由剛好 ndim 個整數構成的元素進行索引,ndim 即其維度。 零維內存視圖可使用空元組進行索引。code

這裏是一個使用非字節格式的例子:
>>> import array
    >>> a = array.array('l', [-11111111, 22222222, -33333333, 44444444])
    >>> m = memoryview(a)
    >>> m[0]
    -11111111
    >>> m[-1]
    44444444
    >>> m[::2].tolist()
    [-11111111, -33333333]

若是下層對象是可寫的,則內存視圖支持一維切片賦值。 改變大小則不被容許:orm

>>> data = bytearray(b'abcefg')
    >>> v = memoryview(data)
    >>> v.readonly
    False
    >>> v[0] = ord(b'z')
    >>> data
    bytearray(b'zbcefg')
    >>> v[1:4] = b'123'
    >>> data
    bytearray(b'z123fg')
    >>> v[2:3] = b'spam'
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ValueError: memoryview assignment: lvalue and rvalue have different structures
    >>> v[2:6] = b'spam'
    >>> data
    bytearray(b'z1spam')

由帶有格式符號 'B', 'b' 或 'c' 的可哈希(只讀)類型構成的一維內存視圖一樣是可哈希的。 哈希定義爲 hash(m) == hash(m.tobytes()):對象

>>> v = memoryview(b'abcefg')
    >>> hash(v) == hash(b'abcefg')
    True
    >>> hash(v[2:4]) == hash(b'ce')
    True
    >>> hash(v[::-2]) == hash(b'abcefg'[::-2])
    True

在 3.3 版更改: 一維內存視圖如今能夠被切片。 帶有格式符號 'B', 'b' 或 'c' 的一維內存視圖如今是可哈希的。索引

在 3.4 版更改: 內存視圖如今會自動註冊爲 collections.abc.Sequence內存

在 3.5 版更改: 內存視圖如今可以使用整數元組進行索引。

memoryview 具備如下一些方法:

__eq__(exporter)

memoryview 與 PEP 3118 中的導出器這二者若是形狀相同,而且若是當使用 struct 語法解讀操做數的相應格式代碼時全部對應值都相同,則它們就是等價的。

對於 tolist() 當前所支持的 struct 格式字符串子集,若是 v.tolist() == w.tolist() 則 v 和 w 相等:

>>> import array
        >>> a = array.array('I', [1, 2, 3, 4, 5])
        >>> b = array.array('d', [1.0, 2.0, 3.0, 4.0, 5.0])
        >>> c = array.array('b', [5, 3, 1])
        >>> x = memoryview(a)
        >>> y = memoryview(b)
        >>> x == a == y == b
        True
        >>> x.tolist() == a.tolist() == y.tolist() == b.tolist()
        True
        >>> z = y[::-2]
        >>> z == c
        True
        >>> z.tolist() == c.tolist()
        True

若是兩邊的格式字符串都不被 struct 模塊所支持,則兩對象比較結果老是不相等(即便格式字符串和緩衝區內容相同):

>>> from ctypes import BigEndianStructure, c_long
        >>> class BEPoint(BigEndianStructure):
        ...     _fields_ = [("x", c_long), ("y", c_long)]
        ...
        >>> point = BEPoint(100, 200)
        >>> a = memoryview(point)
        >>> b = memoryview(point)
        >>> a == point
        False
        >>> a == b
        False

請注意,與浮點數的狀況同樣,對於內存視圖對象來講,v is w 也 並不 意味着 v == w。

在 3.3 版更改: 以前的版本比較原始內存時會忽略條目的格式與邏輯數組結構。

tobytes()

將緩衝區中的數據做爲字節串返回。 這至關於在內存視圖上調用 bytes 構造器。

>>> m = memoryview(b"abc")
        >>> m.tobytes()
        b'abc'
        >>> bytes(m)
        b'abc'

對於非連續數組,結果等於平面化表示的列表,其中全部元素都轉換爲字節串。 tobytes() 支持全部格式字符串,不符合 struct 模塊語法的那些也包括在內。

hex()

返回一個字符串對象,其中分別以兩個十六進制數碼錶示緩衝區裏的每一個字節。

>>> m = memoryview(b"abc")
        >>> m.hex()
        '616263'

3.5 新版功能.

tolist()

將緩衝區內的數據以一個元素列表的形式返回。

>>> memoryview(b'abc').tolist()
        [97, 98, 99]
        >>> import array
        >>> a = array.array('d', [1.1, 2.2, 3.3])
        >>> m = memoryview(a)
        >>> m.tolist()
        [1.1, 2.2, 3.3]

在 3.3 版更改: tolist() 如今支持 struct 模塊語法中的全部單字符原生格式以及多維表示形式。

release()

釋放由內存視圖對象所公開的底層緩衝區。 許多對象在被視圖所獲取時都會採起特殊動做(例如,bytearray 將會暫時禁止調整大小);所以,調用 release() 能夠方便地儘早去除這些限制(並釋聽任何多餘的資源)。

在此方法被調用後,任何對視圖的進一步操做將引起 ValueError (release() 自己除外,它能夠被屢次調用):

>>> m = memoryview(b'abc')
        >>> m.release()
        >>> m[0]
        Traceback (most recent call last):
          File "<stdin>", line 1, in <module>
        ValueError: operation forbidden on released memoryview object

        使用 with 語句,能夠經過上下文管理協議達到相似的效果:
        >>>

        >>> with memoryview(b'abc') as m:
        ...     m[0]
        ...
        97
        >>> m[0]
        Traceback (most recent call last):
          File "<stdin>", line 1, in <module>
        ValueError: operation forbidden on released memoryview object

3.2 新版功能.

cast(format[, shape])

將內存視圖轉化爲新的格式或形狀。 shape 默認爲 [byte_length//new_itemsize],這意味着結果視圖將是一維的。 返回值是一個新的內存視圖,但緩衝區自己不會被複制。 支持的轉化有 1D -> C-contiguous 和 C-contiguous -> 1D。

目標格式僅限於 struct 語法中的單一元素原生格式。 其中一種格式必須爲字節格式 ('B', 'b' 或 'c')。 結果的字節長度必須與原始長度相同。

將 1D/long 轉換爲 1D/unsigned bytes:

>>> import array
        >>> a = array.array('l', [1,2,3])
        >>> x = memoryview(a)
        >>> x.format
        'l'
        >>> x.itemsize
        8
        >>> len(x)
        3
        >>> x.nbytes
        24
        >>> y = x.cast('B')
        >>> y.format
        'B'
        >>> y.itemsize
        1
        >>> len(y)
        24
        >>> y.nbytes
        24

將 1D/unsigned bytes 轉換爲 1D/char:

>>> b = bytearray(b'zyz')
        >>> x = memoryview(b)
        >>> x[0] = b'a'
        Traceback (most recent call last):
          File "<stdin>", line 1, in <module>
        ValueError: memoryview: invalid value for format "B"
        >>> y = x.cast('c')
        >>> y[0] = b'a'
        >>> b
        bytearray(b'ayz')

將 1D/bytes 轉換爲 3D/ints 再轉換爲 1D/signed char:

>>> import struct
       >>> buf = struct.pack("i"*12, *list(range(12)))
       >>> x = memoryview(buf)
       >>> y = x.cast('i', shape=[2,2,3])
       >>> y.tolist()
       [[[0, 1, 2], [3, 4, 5]], [[6, 7, 8], [9, 10, 11]]]
       >>> y.format
       'i'
       >>> y.itemsize
       4
       >>> len(y)
       2
       >>> y.nbytes
       48
       >>> z = y.cast('b')
       >>> z.format
       'b'
       >>> z.itemsize
       1
       >>> len(z)
       48
       >>> z.nbytes
       48

將 1D/unsigned char 轉換爲 2D/unsigned long:

>>> buf = struct.pack("L"*6, *list(range(6)))
        >>> x = memoryview(buf)
        >>> y = x.cast('L', shape=[2,3])
        >>> len(y)
        2
        >>> y.nbytes
        48
        >>> y.tolist()
        [[0, 1, 2], [3, 4, 5]]

3.3 新版功能.

在 3.5 版更改: 當轉換爲字節視圖時,源格式將再也不受限。

還存在一些可用的只讀屬性:

obj

內存視圖的下層對象:

>>> b  = bytearray(b'xyz')
        >>> m = memoryview(b)
        >>> m.obj is b
        True

3.3 新版功能.

nbytes

nbytes == product(shape) * itemsize == len(m.tobytes())。 這是數組在連續表示時將會佔用的空間總字節數。 它不必定等於 len(m):

>>> import array
        >>> a = array.array('i', [1,2,3,4,5])
        >>> m = memoryview(a)
        >>> len(m)
        5
        >>> m.nbytes
        20
        >>> y = m[::2]
        >>> len(y)
        3
        >>> y.nbytes
        12
        >>> len(y.tobytes())
        12

多維數組:

>>> import struct
        >>> buf = struct.pack("d"*12, *[1.5*x for x in range(12)])
        >>> x = memoryview(buf)
        >>> y = x.cast('d', shape=[3,4])
        >>> y.tolist()
        [[0.0, 1.5, 3.0, 4.5], [6.0, 7.5, 9.0, 10.5], [12.0, 13.5, 15.0, 16.5]]
        >>> len(y)
        3
        >>> y.nbytes
        96

3.3 新版功能.

readonly

一個代表內存是否只讀的布爾值。

format

一個字符串,包含視圖中每一個元素的格式(表示爲 struct 模塊樣式)。 內存視圖能夠從具備任意格式字符串的導出器建立,但某些方法 (例如 tolist()) 僅限於原生的單元素格式。

在 3.3 版更改: 格式 'B' 如今會按照 struct 模塊語法來處理。 這意味着 memoryview(b'abc')[0] == b'abc'[0] == 97。

itemsize

memoryview 中每一個元素以字節表示的大小:

>>> import array, struct
        >>> m = memoryview(array.array('H', [32000, 32001, 32002]))
        >>> m.itemsize
        2
        >>> m[0]
        32000
        >>> struct.calcsize('H') == m.itemsize
        True

ndim

一個整數,表示內存所表明的多維數組具備多少個維度。

### shape

一個整數元組,經過 ndim 的長度值給出內存所表明的 N 維數組的形狀。

在 3.3 版更改: 當 ndim = 0 時值爲空元組而再也不爲 None。

strides

一個整數元組,經過 ndim 的長度給出以字節表示的大小,以便訪問數組中每一個維度上的每一個元素。

在 3.3 版更改: 當 ndim = 0 時值爲空元組而再也不爲 None。

suboffsets

供 PIL 風格的數組內部使用。 該值僅做爲參考信息。

c_contiguous

一個代表內存是否爲 C-contiguous 的布爾值。

3.3 新版功能.

f_contiguous

一個代表內存是否爲 Fortran contiguous 的布爾值。

    3.3 新版功能.

contiguous

一個代表內存是否爲 contiguous 的布爾值。

3.3 新版功能.

上一篇文章: Python標準庫---1三、內置類型:二進制序列類型 ( bytes, bytearray)
下一篇文章: Python標準庫---1五、內置類型:集合類型、映射類型
相關文章
相關標籤/搜索