Python
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax and Data Types
-
Section 3: Collections
-
39: Set Operations: Union, Intersection, Difference
-
Section 4: Control Flow
-
Section 5: Functions
-
Section 6: Turtle Graphics and Early Practice Projects
-
Section 7: Working with Files and I/O
-
Section 8: Regular Expressions
-
Section 9: Object-Oriented Python
-
Section 10: Error Handling
-
Section 11: Modules and Packages
-
Section 12: Iterators, Generators, and Functional Tools
-
Section 13: Decorators and Metaprogramming
-
Section 14: Concurrency and Parallelism
-
Section 15: Working with Dates, Times, and Numbers
-
Section 16: Standard Library Deep Dive I: Data Structures
-
Section 17: Standard Library Deep Dive II: System and Introspection
-
Section 18: Standard Library Deep Dive III: Security and Encoding
-
Section 19: Standard Library Deep Dive IV: Text and Data Utilities
-
Section 20: Networking and Web Basics
-
Section 21: Working with Databases
-
Section 22: Testing and Quality
-
Section 23: Advanced Typing
-
Section 24: Context Managers and Resource Handling
-
Section 25: Text, Unicode, and Binary Data
-
Section 26: More Functional and Iteration Tools
-
Section 27: Data Validation and Configuration
-
Section 28: Working with Images and Media
-
Section 29: Property-Based and Documentation Testing
-
Section 30: Packaging and Deployment
-
Section 31: Performance and Internals
-
Section 32: Design Patterns in Python
-
Section 33: GUI Programming
-
Section 34: Security Basics
-
Section 35: Data Structures and Algorithms
-
Section 36: Practical Projects
-
Section 37: Capstone Projects
-
Section 38: Interview and Algorithm Practice
-
Section 39: Writing Idiomatic Python
363: Bit Manipulation Techniques in Python
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, andINVISIBLE = 8. - Create a variable
character_statusand initialize it to 0. - Apply the
POISONEDandINVISIBLEeffects using the OR operator. - Write a check to see if the character is
STUNNEDand print "Character is stunned!" or "Character is not stunned!". - The character drinks an antidote! Use the NOT and AND operators to specifically remove the
POISONEDeffect. - Print the final binary representation of
character_statusto verify onlyINVISIBLEremains.
There are no comments for now.