Best way to overwrite some bits in a particular range

This is done by first masking the bits you want to erase (forcing them to zero while preserving the other bits) before applying the bitwise OR.

Use a bitwise AND with the pattern (in this case) 11100111.

If you already have a "positive" version of the pattern (here this would be 00011000), which is easier to generate, you can obtain the "negative" version 11100111 using what is called 1's complement, available as ~ in Python and most languages with a C-like syntax.


a = 0b01001010
a &= 0b11100111
a |= 0b00010000

The and first zeroes the target bits:

  01001010
& 11100111
  --------
  01000010

then the or fills them with the desired data:

  01000010
| 00010000
  --------
  01010010

I see you got excellent answers in the "bit manipulation" vein. If you have to do a lot of this, though, I would still recommend reading the discussion here and links therefrom, and, as that wiki suggests, a few of the packages found this way (BitVector, BitPacket, bitarray) -- readability is important, and experience shows that removing non-obvious inline code from your application-level flow in favor of calls to well-named APIs enhances it.

If you do decide to go with manipulation, automatic generation of the bit-ranges masks given bit-indices is clearly crucial. I would recommend starting with an "atomic bitmask" with just one 1 bit, built by shifting:

>>> bin(1 << 7)
'0b10000000'

as you see, 1 << 7 has a one followed by 7 zeros -- and therefore:

>>> bin((1 << 7) - 1)
'0b1111111'

(1 << 7) - 1 has exactly 7 ones (you need the parentheses because the priority of the shifting operator << is lower than that of the subtraction operator -) as the least significant bits aka LSB (and of course all zeros left of that).

Given an easy way to make "a bitmask with N ones" (as the LSB), making ones with bits N included to M excluded set and all other cleared is easy -- using named functions for extra readability:

>>> def n_lsb(x): return (1 << x) - 1
... 
>>> def n_to_m(n, m): return n_lsb(n) & ~ n_lsb(m)
... 
>>> bin(n_to_m(7, 3))
'0b1111000'

So, now, to set bits N included to M excluded to a certain pattern, as other answers have shown:

>>> def set_bits(i, n, m, pat): return (i & ~n_to_m(n, m))|(pat<<m)
... 
>>> bin(set_bits(511, 7, 3, 0b0101))
'0b110101111'

While this answer does not, per se, allow you to do anything more than the others, I do hope it can help "teach you to fish" (vs. just giving you a fish;-) and thereby help you (and other readers) in the future.

BTW, I would recommend reducing to a minimum the mix of bitwise and arithmetic operations -- in this A the only arithmetic operation I use is that - 1 in n_lsb, a hopefully very clear case; in more general cases, two's complement arithmetic (what ordinary integer arithmetic looks like when looked at from a bitwise point of view) could be tricky.