MutableBits

The MutableBits class is the mutable version of Bits.

It has almost all of the methods and properties of Bits and adds capabilities for changing the bits in-place.

The new methods are:

Some methods from Bits that return a generator are not allowed as the underlying binary value could change while the generator is still live. For example the Bits.find_all method is not available on MutableBits, but you can use .to_bits().find_all() instead.

You can switch between MutableBits and Bits using the MutableBits.to_bits and Bits.to_mutable_bits methods.f

The reserve and capacity methods can be used to manage the capacity of the MutableBits to avoid unneccesary reallocations, but their use is purely for performance optimization.


class MutableBits(s=None)

A mutable container of binary data.

To construct, use a builder ‘from’ method:

  • MutableBits.from_bytes(b) - Create directly from a bytes object.

  • MutableBits.from_string(s) - Use a formatted string.

  • MutableBits.from_bools(i) - Convert each element in i to a bool.

  • MutableBits.from_zeros(length) - Initialise with length ‘0’ bits.

  • MutableBits.from_ones(length) - Initialise with length ‘1’ bits.

  • MutableBits.from_random(length, [seed]) - Initialise with length pseudo-randomly set bits.

  • MutableBits.from_dtype(dtype, value) - Combine a data type with a value.

  • MutableBits.from_joined(iterable) - Concatenate an iterable of objects.

Using the constructor MutableBits(s) is an alias for MutableBits.from_string(s).

all()

Return True if all bits are equal to 1, otherwise return False.

Returns:

True if all bits are 1, otherwise False.

>>> MutableBits('0b1111').all()
True
>>> MutableBits('0b1011').all()
False
any()

Return True if any bits are equal to 1, otherwise return False.

Returns:

True if any bits are 1, otherwise False.

>>> MutableBits('0b0000').any()
False
>>> MutableBits('0b1000').any()
True
append(bs)

Append bits to the end of the current MutableBits in-place.

Parameters:

bs – The bits to append.

Returns:

self

>>> a = MutableBits('0x0f')
>>> a.append('0x0a')
MutableBits('0x0f0a')
as_bits()

Create and return a Bits instance by moving the MutableBits data.

The data is moved to the new Bits, so this MutableBits will be empty after the operation. This is more efficient than to_bits if you no longer need the MutableBits.

It will try to reclaim any excess memory capacity that the MutableBits may have had.

Returns:

A Bits instance with the same bit data.

>>> a = MutableBits('0b1011')
>>> b = a.as_bits()
>>> a
MutableBits()
>>> b
Bits('0b1101')
byte_swap(byte_length=None)

Change the byte endianness in-place. Returns self.

The whole of the MutableBits will be byte-swapped. It must be a multiple of byte_length long.

Parameters:

byte_length – An int giving the number of bytes in each swap.

Returns:

self

>>> a = MutableBits('0x12345678')
>>> a.byte_swap(2)
MutableBits('0x34127856')
capacity()

Return the number of bits the MutableBits can hold without reallocating memory.

The capacity is always equal to or greater than the current length of the MutableBits. If the length ever exceeds the capacity then memory will have to be reallocated, and the capacity will increase.

It can be helpful as a performance optimization to reserve enough capacity before constructing a large MutableBits incrementally. See also reserve.

clear()

Clear all bits, making the MutableBits empty.

This doesn’t change the allocated capacity, so won’t free up any memory.

count(value)

Count of total number of either zero or one bits.

Parameters:

value – If bool(value) is True, bits set to 1 are counted; otherwise, bits set to 0 are counted.

Returns:

The count of bits set to 1 or 0.

>>> MutableBits('0xef').count(1)
7
ends_with(suffix)

Return whether the current MutableBits ends with suffix.

Parameters:

suffix – The Bits to search for.

Returns:

True if the Bits ends with the suffix, otherwise False.

>>> MutableBits('0b101100').ends_with('0b10-')
True
>>> MutableBits('0b101100').ends_with('0b101')
False
find(bs, /, start=None, end=None, byte_aligned=None)

Find first occurrence of substring bs.

Returns the bit position if found, or None if not found.

Parameters:
  • bs (Union[Bits, MutableBits, str, bytearray, bytes, memoryview]) – The Bits to find.

  • start (int | None) – The starting bit position. Defaults to 0.

  • end (int | None) – The end position. Defaults to len(self).

  • byte_aligned (bool | None) – If True, the Bits will only be found on byte boundaries.

Return type:

int | None

Returns:

The bit position if found, or None if not found.

>>> Bits.from_string('0xc3e').find('0b1111')
6
from_bools()

Create a new instance from an iterable by converting each element to a bool.

Parameters:

i – The iterable to convert to a MutableBits.

a = MutableBits.from_bools([False, 0, 1, "Steven"])  # binary 0011
from_bytes()

Create a new instance from a bytes object.

Parameters:

b – The bytes object to convert to a MutableBits.

a = MutableBits.from_bytes(b"some_bytes_maybe_from_a_file")
classmethod from_dtype(dtype, value, /)

Pack a value according to a data type or data type tuple.

Parameters:
  • dtype (Dtype | str) – The data type to pack.

  • value (Any) – A value appropriate for the data type.

Return type:

MutableBits

Returns:

A newly constructed MutableBits.

a = MutableBits.from_dtype("u8", 17)
b = MutableBits.from_dtype("f16, i4, bool", [2.25, -3, False])
from_joined()

Create a new instance by concatenating a sequence of Bits objects.

This method concatenates a sequence of Bits objects into a single MutableBits object.

Parameters:

sequence – A sequence to concatenate. Items can either be a Bits object, or a string or bytes-like object that could create one via the from_string or from_bytes methods.

a = MutableBits.from_joined([f'u6={x}' for x in range(64)])
b = MutableBits.from_joined(['0x01', 'i4 = -1', b'some_bytes'])
from_ones()

Create a new instance with all bits set to one.

Parameters:

length – The number of bits to set.

>>> MutableBits.from_ones(5)
MutableBits('0b11111')
from_random(seed=None)

Create a new instance with all bits pseudo-randomly set.

Parameters:
  • length – The number of bits to set. Must be positive.

  • seed – An optional seed as a bytes or bytearray.

Returns:

A newly constructed MutableBits with random data.

Note that this uses a pseudo-random number generator and so might not suitable for cryptographic or other more serious purposes.

a = MutableBits.from_random(1000000)  # A million random bits
b = MutableBits.from_random(100, b'a_seed')
from_string()

Create a new instance from a formatted string.

This method initializes a new instance of MutableBits using a formatted string.

Parameters:

s – The formatted string to convert.

Returns:

A newly constructed MutableBits.

a = MutableBits.from_string("0xff01")
b = MutableBits.from_string("0b1")
c = MutableBits.from_string("u12 = 31, f16=-0.25")

The __init__ method for MutableBits redirects to the from_string method and is sometimes more convenient:

a = MutableBits("0xff01")  # MutableBits(s) is equivalent to MutableBits.from_string(s)
from_zeros()

Create a new instance with all bits set to zero.

Parameters:

length – The number of bits to set.

Returns:

A MutableBits object with all bits set to zero.

a = MutableBits.from_zeros(500)  # 500 zero bits
info()

Return a descriptive string with information about the Bits.

Note that the output is designed to be helpful to users and is not considered part of the API. You should not use the output programmatically as it may change even between point versions.

>>> Bits('0b1101').info()
'4 bits: binary = 1101, hex = d, unsigned int = 13, signed int = -3'
Return type:

str

insert(pos, bs)

Inserts another Bits or MutableBits at bit position pos. Returns self.

Parameters:
  • pos – The bit position to insert at.

  • bs – The Bits to insert.

Returns:

self

Raises ValueError if pos < 0 or pos > len(self).

>>> a = MutableBits('0b1011')
>>> a.insert(2, '0b00')
MutableBits('0b100011')
invert(pos=None)

Return the MutableBits with one or many bits inverted between 0 and 1.

Parameters:

pos – Either a single bit position or an iterable of bit positions.

Returns:

self

Raises IndexError if pos < -len(self) or pos >= len(self).

>>> a = MutableBits('0b10111')
>>> a.invert(1)
MutableBits('0b11111')
>>> a.invert([0, 2])
MutableBits('0b01011')
>>> a.invert()
MutableBits('0b10100')
pp(dtype1=None, dtype2=None, groups=None, width=80, show_offset=True, stream=<_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>)

Pretty print the Bits’s value.

Parameters:
  • dtype1 (str | Dtype | None) – First data type to display.

  • dtype2 (str | Dtype | None) – Optional second data type.

  • groups (int | None) – How many groups of bits to display on each line. This overrides any value given for width.

  • width (int) – Max width of printed lines. Defaults to 80, but ignored if groups parameter is set. A single group will always be printed per line even if it exceeds the max width.

  • show_offset (bool) – If True (the default) shows the bit offset in the first column of each line.

  • stream (TextIO) – A TextIO object with a write() method. Defaults to sys.stdout.

Return type:

None

s.pp('hex4', groups=6)
s.pp('bin', 'hex', show_offset=False)
prepend(bs)

Prepend bits to the beginning of the current MutableBits in-place.

Parameters:

bs – The bits to prepend.

Returns:

self

>>> a = MutableBits('0x0f')
>>> a.prepend('0x0a')
MutableBits('0x0a0f')
replace(old, new, /, start=None, end=None, count=None, byte_aligned=None)

Replaces all occurrences of old with new. Returns self.

Parameters:
  • old (Union[Bits, MutableBits, str, bytearray, bytes, memoryview]) – The Bits or to replace.

  • new (Union[Bits, MutableBits, str, bytearray, bytes, memoryview]) – The replacement Bits.

  • start (int | None) – Any occurrences that start before this bit position will not be replaced.

  • end (int | None) – Any occurrences that finish after this bit position will not be replaced.

  • count (int | None) – The maximum number of replacements to make. Defaults to all.

  • byte_aligned (bool | None) – If True, replacements will only be made on byte boundaries.

Return type:

MutableBits

Returns:

self

Raises:

ValueError – if old is empty or if start or end are out of range.

>>> s = MutableBits('0b10011')
>>> s.replace('0b1', '0xf')
MutableBits('0b11110011111111')
reserve(additional)

Reserve memory for at least additional more bits to be appended to the MutableBits.

This can be helpful as a performance optimization to avoid multiple memory reallocations when constructing a large MutableBits incrementally. If enough memory is already reserved then this method will have no effect. See also capacity.

Parameters:

additional – The number of bits that can be appended without any further memory reallocations.

reverse()

Reverse bits in-place.

Returns:

self

>>> a = MutableBits('0b1011')
>>> a.reverse()
MutableBits('0b1101')
rfind(bs, /, start=None, end=None, byte_aligned=None)

Find final occurrence of substring bs.

Returns the bit position if found, or None if not found. Note that start and end define a slice in the usual way, so the occurrence of bs closest to the end posistion will be found.

Parameters:
  • bs (Union[Bits, MutableBits, str, bytearray, bytes, memoryview]) – The Bits to find.

  • start (int | None) – The starting bit position of the slice to search. Defaults to 0.

  • end (int | None) – The end bit position of the slice to search. Defaults to len(self).

  • byte_aligned (bool | None) – If True, the Bits will only be found on byte boundaries.

Return type:

int | None

Returns:

The bit position if found, or None if not found.

Raises ValueError if bs is empty.

>>> Bits('0b110110').rfind('0b1')
4
>>> Bits('0b110110').rfind('0b0')
5
rol(n, start=None, end=None)

Rotates bit pattern to the left. Returns self.

Parameters:
  • n – The number of bits to rotate by.

  • start – Start of slice to rotate. Defaults to 0.

  • end – End of slice to rotate. Defaults to len(self).

Returns:

self

Raises ValueError if n < 0.

>>> a = MutableBits('0b1011')
>>> a.rol(2)
MutableBits('0b1110')
ror(n, start=None, end=None)

Rotates bit pattern to the right. Returns self.

Parameters:
  • n – The number of bits to rotate by.

  • start – Start of slice to rotate. Defaults to 0.

  • end – End of slice to rotate. Defaults to len(self).

Returns:

self

Raises ValueError if n < 0.

>>> a = MutableBits('0b1011')
>>> a.ror(1)
MutableBits('0b1101')
set(value, pos)

Set one or many bits set to 1 or 0. Returns self.

Parameters:
  • value – If bool(value) is True, bits are set to 1, otherwise they are set to 0.

  • pos – Either a single bit position or an iterable of bit positions.

Returns:

self

Raises:

IndexError – if pos < -len(self) or pos >= len(self).

>>> a = MutableBits.from_zeros(10)
>>> a.set(1, 5)
MutableBits('0b0000010000')
>>> a.set(1, [-1, -2])
MutableBits('0b0000010011')
>>> a.set(0, range(8, 10))
MutableBits('0b0000010000')
starts_with(prefix)

Return whether the current MutableBits starts with prefix.

Parameters:

prefix – The Bits to search for.

Returns:

True if the Bits starts with the prefix, otherwise False.

>>> MutableBits('0b101100').starts_with('0b101')
True
>>> MutableBits('0b101100').starts_with('0b100')
False
to_bits()

Create and return a Bits instance from a copy of the MutableBits data.

This copies the underlying binary data, giving a new independent Bits object. If you no longer need the MutableBits, consider using as_bits instead to avoid the copy.

Returns:

A new Bits instance with the same bit data.

>>> a = MutableBits('0b1011')
>>> b = a.to_bits()
>>> a
MutableBits('0b1011')
>>> b
Bits('0b1101')
to_bytes()

Return the MutableBits as bytes, padding with zero bits if needed.

Up to seven zero bits will be added at the end to byte align.

Returns:

The MutableBits as bytes.

unpack(dtype, /, start=None, end=None)

Interpret the Bits as a given data type or list of data types.

If a single Dtype is given then a single value will be returned, otherwise a list of values will be returned. A single Dtype with no length can be used to interpret the whole Bits - in this common case properties are provided as a shortcut. For example instead of b.unpack('bin') you can use b.bin.

Parameters:
  • dtype (Dtype | str | Sequence[Dtype | str]) – The data type used to interpret the Bits.

  • start (int | None) – The starting bit position. Defaults to 0.

  • end (int | None) – The end position. Defaults to len(self).

Return type:

Any | list[Any]

Returns:

The interpreted value(s).

>>> s = Bits('0xdeadbeef')
>>> s.unpack(['bin4', 'u28'])
['1101', 246267631]
>>> s.unpack(['f16', '[u4; 4]'])
[-427.25, (11, 14, 14, 15)]
>>> s.unpack('i')
-559038737
>>> s.i
-559038737
property bin

The MutableBits as a binary string. Read and write.

property bits

The MutableBits as a Bits object. Read and write.

property bool

The MutableBits as a bool (True or False). Read and write.

property bytes

The MutableBits as a bytes object. Read and write.

property f

The MutableBits as an IEEE floating point number. Read and write.

property f_be

The MutableBits as an IEEE floating point number in big-endian byte order. Read and write.

property f_le

The MutableBits as an IEEE floating point number in little-endian byte order. Read and write.

property f_ne

The MutableBits as an IEEE floating point number in native-endian (i.e. little-endian-endian) byte order. Read and write.

property hex

The MutableBits as a hexadecimal string. Read and write.

property i

The MutableBits as a two’s complement signed int. Read and write.

property i_be

The MutableBits as a two’s complement signed int in big-endian byte order. Read and write.

property i_le

The MutableBits as a two’s complement signed int in little-endian byte order. Read and write.

property i_ne

The MutableBits as a two’s complement signed int in native-endian (i.e. little-endian-endian) byte order. Read and write.

property oct

The MutableBits as an octal string. Read and write.

property pad

The MutableBits as a skipped section of padding. Read and write.

property u

The MutableBits as a two’s complement unsigned int. Read and write.

property u_be

The MutableBits as a two’s complement unsigned int in big-endian byte order. Read and write.

property u_le

The MutableBits as a two’s complement unsigned int in little-endian byte order. Read and write.

property u_ne

The MutableBits as a two’s complement unsigned int in native-endian (i.e. little-endian-endian) byte order. Read and write.