Code of the Day
AdvancedData Engineering

Bitwise operations and advanced boolean patterns

Use flags, bitmasks, any/all, walrus, and custom truth-value testing to write expressive, efficient boolean logic.

PythonAdvanced9 min read
By the end of this lesson you will be able to:
  • Apply bitwise operators to test and manipulate permission flags
  • Use any() and all() for concise collection-level boolean tests
  • Implement __bool__ and __len__ for custom truth-value testing
  • Apply the walrus operator in boolean contexts to avoid re-evaluation

Boolean logic in Python runs deeper than and/or/not. This lesson covers the — where individual bits encode flags and masks — and the collection-level tools (any, all) and language features (:=, __bool__) that let you express complex boolean logic in one readable line instead of many nested if blocks.

Bitwise operators

Each operator works on individual bits of integer values:

OperatorNameExampleResult
&AND0b1100 & 0b10100b1000
|OR0b1100 | 0b10100b1110
^XOR0b1100 ^ 0b10100b0110
~NOT (invert)~0b0001-2 (two's complement)
<<Left shift1 << 38
>>Right shift16 >> 24
a = 0b1100   # 12
b = 0b1010   # 10
print(bin(a & b))   # 0b1000  (8)
print(bin(a | b))   # 0b1110  (14)
print(bin(a ^ b))   # 0b0110  (6)
print(1 << 4)       # 16  (2^4)

Flags and bitmasks

The canonical use of bitwise ops is permission flags — compact sets where each bit represents one boolean attribute:

READ  = 0b001   # 1
WRITE = 0b010   # 2
EXEC  = 0b100   # 4

# Grant read + write
perms = READ | WRITE    # 0b011 = 3

# Test for a flag
has_write = bool(perms & WRITE)   # True
has_exec  = bool(perms & EXEC)    # False

# Set a flag
perms = perms | EXEC              # add execute

# Clear a flag with bitwise AND + NOT
perms = perms & ~WRITE            # remove write

This pattern appears in OS permissions (os.stat mode bits), network protocol headers, game entity-component systems, and event-driven libraries everywhere.

Flag operationsPython

Implement has_flag(value, flag), set_flag(value, flag), and clear_flag(value, flag) using bitwise operators. has_flag returns True if the flag bit is set. set_flag returns value with the flag bit set. clear_flag returns value with the flag bit cleared.

has_flag(0b011, 0b010)Trueclear_flag(0b011, 0b001)2

any() and all() for collection-level tests

Instead of a manual loop with an accumulator, use the built-ins:

scores = [85, 92, 78, 95, 61]

# all() short-circuits on the first False
if all(s >= 60 for s in scores):
    print("everyone passed")

# any() short-circuits on the first True
if any(s >= 90 for s in scores):
    print("at least one high achiever")

# both return True on an empty iterable (all) / False (any) — consistent
print(all(s > 0 for s in []))   # True  (vacuous truth)
print(any(s > 0 for s in []))   # False

any/all accept any iterable, compose naturally with generators, and avoid building an intermediate list.

Validate a list of recordsPython

Write all_valid(records) that returns True only if every record dict has a non-empty "name" (str) and a non-negative "score" (int or float). Use all() and any().

all_valid([{"name": "Alice", "score": 90}])Trueall_valid([{"name": "", "score": 90}])False

Custom truth-value testing: bool and len

When Python evaluates an object in a boolean context (if obj:, while obj:, not obj), it calls __bool__ first, then __len__ as a fallback. Implementing these makes your objects feel idiomatic:

class Buffer:
    def __init__(self, data):
        self.data = data

    def __len__(self):
        return len(self.data)

    # __bool__ is called first; falls back to len(obj) != 0 if absent
    def __bool__(self):
        return len(self.data) > 0

buf = Buffer(b"")
print(bool(buf))   # False — empty buffer is falsy
print(bool(Buffer(b"\x00")))  # True — one byte, truthy

The pattern appears throughout the standard library: an empty list, dict, str, or bytes is falsy; non-empty is truthy. Your own containers should do the same.

The walrus operator in boolean contexts

:= (walrus, "assignment expression") assigns and returns a value in a single expression. It shines in loops and conditions where you'd otherwise compute something twice:

import re

# without walrus: compute match, then check, then use
match = re.search(r"\d+", line)
if match:
    print(match.group())

# with walrus: assign and test in one go
if m := re.search(r"\d+", line):
    print(m.group())

# very clean in while loops reading chunks from a file
with open("data.bin", "rb") as f:
    while chunk := f.read(4096):
        process(chunk)

Use walrus only where the double-evaluation problem is real — don't reach for it just because it looks clever. A plain two-liner is clearer when the expression is side-effect-free and cheap to compute.

Where to go next

You've handled bytes, stored data, and mastered boolean logic. The last piece of any real pipeline is navigating the filesystem. Next: Filesystem and path manipulation.

Finished reading? Mark it complete to track your progress.

On this page