Skip to Content
Course content

363: Bit Manipulation Techniques in Python

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I was digging through some legacy code for a project recently and came across a system that managed user permissions using a single integer instead of a list of strings or a database table. My first instinct was, "Who does this? It's unreadable." But as I started poking at it, I realized it was an incredibly efficient way to handle state. Let's walk through how this actually works by trying to build a simplified version of that system ourselves.

The problem with lists for flags

Normally, if I wanted to track if a user has "Read", "Write", and "Execute" permissions, I'd probably do something like this:

permissions = ["READ", "WRITE"]
if "WRITE" in permissions:
    print("You can edit this!")

That's fine for a small script. But if you're managing millions of users in a high-performance environment, storing lists of strings is a memory nightmare. I wondered if I could pack all these booleans into a single number. Since a number is just a sequence of bits (0s and 1s) under the hood, each bit can act as a toggle.

Mapping permissions to bits

To do this, I need to assign each permission to a power of two. Why powers of two? Because they each occupy exactly one unique bit position in binary.

READ    = 1  # 001 in binary
WRITE   = 2  # 010 in binary
EXECUTE = 4  # 100 in binary
DELETE  = 8  # 1000 in binary

Now, let's say I want to give a user both READ and WRITE permissions. I'll try using the bitwise OR operator (|). This operator compares bits and returns a 1 if either bit is 1.

user_perms = READ | WRITE
print(bin(user_perms)) 
# Output: 0b11

Looking at 0b11, I can see the first and second bits are flipped on. It's like a compact checklist. If I add EXECUTE (user_perms | EXECUTE), I get 0b111. I've just stored three different boolean flags in one tiny integer.

Checking for a specific flag

The tricky part is checking if a user has a specific permission without accidentally triggering others. If I just check if user_perms == WRITE:, it will fail because user_perms is actually 3 (READ and WRITE), not 2. I need a way to "mask" the bits I don't care about.

I'll try the bitwise AND operator (&). This only returns a 1 if both bits are 1.

user_perms = 3 # (READ | WRITE)

# Let's check if they have WRITE (2)
result = user_perms & WRITE
print(bin(result)) # Output: 0b10 (Which is 2!)

# Let's check if they have EXECUTE (4)
result = user_perms & EXECUTE
print(bin(result)) # Output: 0b0 (Which is 0!)

This is the "Aha!" moment. If (user_perms & FLAG) is non-zero, the flag is set. If it's zero, it's not. It's a surgical way to probe a single bit.

Toggling and stripping permissions

What if I want to remove a permission? I tried using the XOR operator (^) first. XOR returns 1 only if the bits are different.

user_perms = 3 # READ and WRITE
user_perms = user_perms ^ WRITE 
print(bin(user_perms)) # Output: 0b01 (Now only READ is left)

Wait, there's a catch. XOR toggles. If the user didn't have WRITE permission and I XORed it, I would accidentally give it to them. That's dangerous for a security system. I need a way to ensure a bit is turned off regardless of its current state.

I can combine the bitwise NOT (~) with AND. The NOT operator flips all bits. So, ~WRITE creates a mask where every bit is 1 except the WRITE bit.

# Ensure WRITE is gone, regardless of current state
user_perms = user_perms & ~WRITE
print(bin(user_perms))

By ANDing the permissions with a mask that has a 0 at the WRITE position, I've effectively forced that specific bit to 0 while leaving everything else untouched. It's a much safer way to revoke access.




📋 Practical Task

Build a Character Status Effect Mask

In a role-playing game, characters can have multiple status effects (Poisoned, Stunned, Frozen, Invisible). Instead of using four different boolean variables, create a system using bit manipulation.

  • Define four constants: POISONED = 1, STUNNED = 2, FROZEN = 4, and INVISIBLE = 8.
  • Create a variable character_status and initialize it to 0.
  • Apply the POISONED and INVISIBLE effects using the OR operator.
  • Write a check to see if the character is STUNNED and print "Character is stunned!" or "Character is not stunned!".
  • The character drinks an antidote! Use the NOT and AND operators to specifically remove the POISONED effect.
  • Print the final binary representation of character_status to verify only INVISIBLE remains.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.