Bitwise Operators & Flags
Manipulate individual bits with & | ^ ~ << >> — and model permission flags cleanly.
Bitwise operators work on the binary representation of integers, one bit at a time.
| Operator | Name | Example |
|---|---|---|
& | AND (both 1) | 0b1100 & 0b1010 = 0b1000 |
| | OR (either 1) | 0b1100 | 0b1010 = 0b1110 |
^ | XOR (differ) | 0b1100 ^ 0b1010 = 0b0110 |
~ | NOT (invert) | ~5 = -6 |
<< | shift left | 1 << 4 = 16 |
>> | shift right | 16 >> 2 = 4 |
flags = 0b0000
flags |= 0b0010 # set a bit
print(bin(flags)) # 0b10
print(flags & 0b0010) # 2 -> the bit is on
flags &= ~0b0010 # clear that bit
print(bin(flags)) # 0b0You rarely write raw bits
In modern Python, enum.IntFlag gives you named, combinable flags with all the readability of an enum and all the speed of bitwise maths. That is almost always the right tool — the raw operators below are what it is built on.
Example
from enum import IntFlag, auto
class Permission(IntFlag):
READ = auto() # 1
WRITE = auto() # 2
EXECUTE = auto() # 4
ALL = READ | WRITE | EXECUTE
# Combine with | , test with & , remove with & ~
role = Permission.READ | Permission.WRITE
print('role :', role) # Permission.READ|WRITE
print('can write? :', Permission.WRITE in role) # True
print('can execute? :', Permission.EXECUTE in role) # False
role |= Permission.EXECUTE # grant execute
role &= ~Permission.WRITE # revoke write
print('after changes :', role) # READ|EXECUTE
print('is ALL? :', role == Permission.ALL) # False
print('raw value :', int(role)) # 5
# Output:
# role : Permission.READ|WRITE
# can write? : True
# can execute? : False
# after changes : Permission.READ|EXECUTE
# is ALL? : False
# raw value : 5When to use it
- A permission system stores read/write/execute flags as bits in an integer and checks them with &.
- A network library extracts the high and low bytes of a 16-bit port number using bit-shifts and masks.
- A game engine uses XOR (^) to toggle a feature flag bit without needing an explicit if statement.
More examples
Bitwise AND, OR, XOR
Shows AND, OR, and XOR in binary notation so the bit-level effect is visible.
a = 0b1010 # 10
b = 0b1100 # 12
print(bin(a & b)) # 0b1000 (AND: both bits set)
print(bin(a | b)) # 0b1110 (OR: either bit set)
print(bin(a ^ b)) # 0b0110 (XOR: exactly one set)Permission flags with bitmasks
Models Unix-style permission flags as bit fields using OR to set and AND to query them.
READ = 0b001 # 1
WRITE = 0b010 # 2
EXECUTE = 0b100 # 4
user_perms = READ | WRITE # 3
print(bool(user_perms & READ)) # True
print(bool(user_perms & EXECUTE)) # False
user_perms |= EXECUTE # grant execute
print(bin(user_perms)) # 0b111Left and right bit-shifts
Shows left/right shifts as fast powers-of-two scaling and uses them to split a word into bytes.
x = 1
print(x << 4) # 16 (multiply by 2^4)
print(256 >> 3) # 32 (divide by 2^3)
# Extract high/low bytes of a 16-bit value:
value = 0xABCD
high = (value >> 8) & 0xFF
low = value & 0xFF
print(hex(high), hex(low)) # 0xab 0xcd
Discussion