Bitarray objects support the buffer protocol. They can both export their own buffer, as well as import another object's buffer.
Here is an example where the bitarray's buffer is exported:
>>> from bitarray import bitarray
>>> a = bitarray('01000001 01000010 01000011', endian='big')
>>> v = memoryview(a)
>>> v.tobytes()
b'ABC'
>>> v[1] = 255
>>> a
bitarray('010000011111111101000011')Note that it is possible to change the shared buffer from both a and v:
>>> a[6] = 1
>>> v.tobytes()
b'C\xffC'However, as a's buffer is shared, it is not possible to resize it:
>>> a.append(0)
Traceback (most recent call last):
...
BufferError: cannot resize bitarray that is exporting buffersWhen exporting the buffer of a frozenbitarray, it is not possible to
change its memoryview either:
>>> from bitarray import frozenbitarray
>>> a = frozenbitarray('01000001 01000010')
>>> v = memoryview(a)
>>> v.readonly
True
>>> v[0] = 15
Traceback (most recent call last):
...
TypeError: cannot modify read-only memoryAs of bitarray version 2.3, it is also possible to import the buffer from an object which exposes its buffer. Here the bytearray:
>>> c = bytearray([0x41, 0xff, 0x01])
>>> a = bitarray(buffer=c, endian='big')
>>> a
bitarray('010000011111111100000001')
>>> a <<= 3 # shift all bits by 3 to the left
>>> c
bytearray(b'\x0f\xf8\x08')
>>> a[20:] = 1
>>> a
bitarray('000011111111100000001111')Again, the shared buffer can be represented and modify by either object a
and c. When importing a buffer into a bitarray, the length of the
bitarray will always be multiple of 8 bits, as buffers are bases on bytes.
Also, we may specify the endianness of the bitarray:
>>> b = bitarray(buffer=c, endian='little')
>>> b
bitarray('111100000001111111110000')The bytearray c is now exporting its buffer twice:
to big-endian bitarray a, and a little-endian bitarray b.
At this point all three object a, b and c share the same buffer.
Using the .buffer_info() method, we can actually verify that the
bitarrays a and b point to the same address:
>>> def address(a):
... info = a.buffer_info()
... return info[0] # using bitarray 3.7, we can also: info.address
>>> assert address(a) == address(b)As bitarray's expose their buffer, we can also directly create a bitarray which imports the buffer from another bitarray:
>>> a = bitarray(32)
>>> b = bitarray(buffer=a)
>>> # the buffer address is the same
>>> assert address(a) == address(b)
>>> a.setall(0)
>>> assert a == b
>>> b[::7] = 1
>>> assert a == b
>>> a
bitarray('10000001000000100000010000001000')We can also create bitarrays which share part of the buffer. Let's create
a large bitarray a, and then have b and c share different portions
of a's buffer:
>>> a = bitarray(1 << 23)
>>> a.setall(0)
>>> b = bitarray(buffer=memoryview(a)[0x10000:0x30000])
>>> assert address(a) + 0x10000 == address(b)
>>> c = bitarray(buffer=memoryview(a)[0x20000:0x50000])
>>> assert address(a) + 0x20000 == address(c)
>>> c[0] = 1
>>> assert b[8 * 0x10000] == 1
>>> assert a[8 * 0x20000] == 1Finally, importing buffers allows creating bitarrays that are memory mapped to a file. Please see the mmapped-file.py example.