Abstract
This PEP proposes adding a new built‑in factory function, mutableint(), which creates a mutable integer object(PyMutableLongObject) supporting:
● Direct bit indexing (x[i]→ get bit,x[i] = b→ set bit).
● Bit slicing (x[i:j]→ get/set contiguous bit ranges).
● Arithmetic identical to int, but preserving the mutableint type when any operand is a mutableint.
The existing int type remains immutable and unchanged, ensuring full backward compatibility.
Motivation
Bit manipulation is common in:
● Binary protocol parsing
● Cryptography
● Compression algorithms
● Embedded systems
Currently, bit access requires verbose masking and shifting:
x = 13
bit = (x >> 3) & 1
x = x | (1 << 5)
Proposed:
from builtins import mutableint
x = mutableint(13)
print(x[3]) # 1
x[5] = 1 # grows integer automatically
This is shorter, clearer, and more Pythonic.
Rationale
● Keeps int immutable by default — no risk to existing code.
● Provides an explicit opt‑in for mutability.
● Preserves Python’s arithmetic semantics while extending usability for bit‑level operations.
● Elegant numerical integer scaling from 1 bit to arbitrary length and precision.
● Avoids external dependencies (bitarray, numpy) for basic bit level manipulation.
Specification
Factory Function
mutableint(value=0) → MutableInt
● Returns a new PyMutableLongObjectinstance.
● Accepts any value convertible to int.
Bit Indexing
● x[i]returns the bit at position i(0 = LSB).
● x[i] = b sets the bit at position i to 0 or 1.
● Negative indices raise IndexError.
Bit Slicing
● x[i:j]returns a new mutableint representing bits from i(inclusive) to j(exclusive).
● x[i:j] = y sets that range of bits to the value y.
● Slices beyond the current bit length pad with zeros automatically.
Bit Length
● mutableint.bit_length()returns the total number of binary digits in the value, including leading zeros up to the current width.
● This differs from int.bit_length() which ignores leading zeros.
Example:
x = mutableint(0b00101) # width = 5 bits
print(x.bit_length()) # 5
Arithmetic Semantics
● All arithmetic operations (+,-,*,//,%,**, bitwise ops, shifts) behave exactly like int.
● Type preservation rule:
○ If any integer operand is a mutableint, the result is a mutableint.
○ The result’s bit width grows automatically if needed (arbitrary precision preserved).
● Example:
a = mutableint(5)
b = 10
c = a + b
print(type(c)) # <class ‘mutableint’>
Examples
from builtins import mutableint
x = mutableint(0b1011)
print(x[0]) # 1
print(x[2]) # 0
x[2] = 1
print(bin(x)) # 0b1111
x[5] = 1
print(bin(x)) # 0b1001111
print(x[0:4]) # mutableint(15)
x[0:4] = 0b0101
print(bin(x)) # 0b1000101
Arithmetic preserves type
m = mutableint(3)
n = m + 5
print(type(n)) # <class ‘mutableint’>
Backward Compatibility
● No changes to int semantics.
● No existing code breaks.
● Mutability is explicit and opt‑in.
Implementation Notes
● Introduce a new C type:PyMutableLongObject.
● Share most of PyLongObject’s implementation for storage and arithmetic.
● Add:
○ _getitem_/__setitem__for bit access.
○ Slice handling for bit ranges with zero padding.
○ .bit_length() override to include leading zeros.
○ Arithmetic methods that preserve mutableint type when applicable.
● Ensure thread safety for in‑place updates.
Rejected Alternatives
● Making int mutable globally — breaks Python’s immutability model for numbers.
● Adding bit access to int without mutability — less useful for in‑place updates.
● Using external libraries — adds dependencies for a core numeric feature.
Next Steps
● Build a CPython proof‑of‑concept for PyMutableLongObject.
● Post this PEP draft todiscuss.python.org for feedback.