Another interesting sequence type, Python provides is memoryview
. This is completely different than the other sequence types so far discussed.
Objects of 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 memoryview
object.
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 bytes
and 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 memoryview
objects?
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).
Create memoryview
object
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:
Syntax: memoryview(obj)
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
object
Like bytes
and bytearray
; 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 memoryview
object:
>>> byv[0] 66 >>> byv[-1] 33 >>>
Modify memoryview
object’s elements
Beauty of 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[0] = 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[0] = 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 memoryview
object.
We will discuss more Python in my upcoming Articles.
/Shijit/