Another interesting sequence type, Python provides is
memoryview. This is completely different than the other sequence types so far discussed.
memoryview class is allowed to access the internal memory of the objects where these objects are referencing. In C language, it is possible to access the memory using pointer variables; in Python; we use
memoryview to access it’s’ referencing memory. This doesn’t mean that we can access the internal memory of all the objects using
memoryview objects. An object which supports the Buffer Protocol only allows to access its’ memory through
What is Buffer Protocol?
Buffer Protocol allows exporting an interface to access internal memory (or buffer). And allows getting the pointer to the internal memory. The classes that implement buffer interfaces are allowed to expose their objects’ internal buffer.
The built-in types
bytearray supports this protocol and objects of these classes are allowed to expose internal buffer to allow to directly access the data. To know about these sequence types, I recommend you to read “Python – bytes – A quick walk through with Examples” and “Python – bytearray – A quick walk through with working Examples” Articles.
Why it is required to use
Sometimes, it is required to access the memory directly; to avoid data duplication. I know it is a little bit confusing. I will try to explain this with an example.
When you do Image Processing, you have the image data and you have the functions to process the image data. Every time you pass image data to the functions; inside the function, have another copy of image data, and the function applies the image processing on the copy of image data; not on the original data. And returns a copy of it.
You do not see much difference in Performance or Memory utilization; when you deal with a small amount of data. But when you deal with a large amount of data; DEFINITELY it will consume a lot of your System resources to process the data and DIRECTLY its affects the Performance of the System. So, there must be a way to process the data directly instead of on the copy of the data. That is why Buffer Protocol allows to direct access the memory (or buffer).
memoryview object is a reference to another object’s internal buffer (or memory). To create
memoryview object, we must use memoryview class’s constructor. The Syntax of the constructor looks like below:
Where obj is the class’s object which supports Buffer Protocol. As I mentioned above, only bytes and bytesarray built-in types are supporting Buffer Protocol. So, we can pass only objects of these two types into the memoryview constructor.
>>> byv = memoryview(b"Bytes!") >>> byv <memory at 0x7f434cb7d7c8> >>>
Observe that, from the above statements;
memoryview object “byv” was created, which references to
bytes object. And it prints the memory location of it. You MUST NOTICE that “byv” object displays the memory location of it; and inside of it, referencing where
bytes object stores its’ data.
If you have your own class, which supports Buffer Protocol; you can create
memoryview objects referencing your class’s objects.
If you attempt to create a
memoryview object; passing a class’s object which is not supported Buffer Protocol; you will see a TypeError message. For example, string objects are not supporting Buffer Protocol. If you attempt to create a
memoryview object; referencing string object; you will see below Error message:
>>> sv = memoryview("String!") Traceback (most recent call last): File "", line 1, in TypeError: memoryview: a bytes-like object is required, not 'str' >>>
Accessing elements from
memoryview objects are allowed to access its’ data using the index operator. Index values start from “0” to access the data from the beginning; negative index “-1” starts from the end to access the data from the end. For example, the below statements display the first and last byte from
>>> byv 66 >>> byv[-1] 33 >>>
memoryview object’s elements
memoryview object is; it allows to deal with the data directly. We can access and modify the data directly into the memory. This is a great feature. But, there are some restrictions here.
For example, from the above statements; we have created a
bytes object and get the address of its’ data buffer. We have the address of the memory; so, we can directly modify the data. But, it’s not TRUE in this case. Because
bytes are mutable; we can’t change its’ data once it has been created. If
memoryview allowed to modify the data of bytes objects; there is a flaw in the design of Buffer Protocol. Keeping this in mind; it was designed in such a way that; Buffer Protocol doesn’t allow to modify READ ONLY memory; the memory of mutable objects; in this case
bytes object’s data. If you attempt to modify the mutable object’s data; you will get below Error:
>>> byv = 98 Traceback (most recent call last): File "", line 1, in TypeError: cannot modify read-only memory >>>
But, how do we know whether the memory is read-only.? memoryview provides a property “readonly”; which tells, whether its’ object is referencing a read-only memory. See, below statement:
>>> byv.readonly True
Lets’ try to modify
bytearray object’s data.
>>> bya = memoryview(bytearray(b"Byte Array!")) >>> if bya.readonly: ... print("Access denied!") ... else: ... bya = 98 ... >>> bya <memory at 0x7f434cb7d948>
The above statements, attempt to modify the memory data, if it is NOT read-only. It seems, the first byte “B” was modified with the value “b” (ASCII value – 98). But, how to print this.? We can use
bytes object to print this. Below statement shows how to convert this and print:
>>> bytes(bya) b'byte Array!' >>>
Observe that, the text, “Byte Array!” was modified to “byte Array!” using
We will discuss more Python in my upcoming Articles.