Bitwise Operators
Bitwise operators work directly on the binary representation of integers, bit by bit, rather than on the numbers as a whole. They show up less often than arithmetic operators in everyday scripts, but they are essential for working with flags, masks, low-level protocols, and performance-sensitive numeric tricks.
The operators
Operator | Name | Description |
|---|---|---|
| AND | Bit is |
| OR | Bit is |
| XOR | Bit is |
| NOT | Flips every bit (inverts |
| Left shift | Shifts bits left, filling with |
| Right shift | Shifts bits right (sign-extending for negatives) |
Binary representation, briefly
Every integer is stored as a sequence of bits. Python lets you inspect this with the built-in bin() function, and write binary literals directly with a 0b prefix.
Looking at bits
a = 0b1100 # 12 b = 0b1010 # 10 print(bin(a)) # '0b1100' print(bin(b)) # '0b1010' print(bin(a & b)) # AND print(bin(a | b)) # OR print(bin(a ^ b)) # XOR
0b1100 0b1010 0b1000 0b1110 0b110
~ and two's complement
x = 5 print(~x) # -6 (because ~x == -x - 1) # Simulating an 8-bit NOT by masking to 8 bits byte_value = 0b00000101 # 5 inverted_8bit = ~byte_value & 0xFF print(bin(inverted_8bit)) # 0b11111010
Practical use case: flags and masks
Bitwise operators are the standard way to pack several boolean flags into a single integer — classic examples include Unix file permission bits or feature flags in a config value. Each bit position represents one on/off setting.
Permission flags with bitmasks
READ = 0b100 # 4 WRITE = 0b010 # 2 EXECUTE = 0b001 # 1 # Grant read and write, but not execute permissions = READ | WRITE print(bin(permissions)) # 0b110 # Check if WRITE is set has_write = bool(permissions & WRITE) print(has_write) # True # Revoke WRITE (clear that bit) permissions &= ~WRITE print(bin(permissions)) # 0b100 # Toggle EXECUTE on/off permissions ^= EXECUTE print(bin(permissions)) # 0b101
Use
|to set (turn on) a flag.Use
&with the flag to check whether it is set.Use
&= ~flagto clear (turn off) a flag.Use
^=to toggle a flag between on and off.
Practical use case: fast multiply/divide by powers of 2
Shifting bits left by n positions is equivalent to multiplying by 2**n, and shifting right by n positions is equivalent to integer division by 2**n. CPU-level shifts are cheap, so this pattern shows up in performance-sensitive code and in bit-manipulation puzzles.
Shifts as multiply/divide
value = 5 print(value << 1) # 10 (5 * 2) print(value << 3) # 40 (5 * 8) print(value >> 1) # 2 (5 // 2, rounds toward negative infinity) negative = -20 print(negative >> 2) # -5 (-20 // 4)