← Home

026. Membership Operators

Containment checks for collections and sequences

026. Membership Operators

RAM Manager — Allowlist and Blocklist Checks

Aryan’s RAM manager has two lists:

  • Protected processes (never kill): {"kernel", "systemd", "launchd"}
  • Known high-memory patterns in process names: substrings like "leak", "zombie"

He writes is_protected(name, protected_set) to check if a name is in the protected set, and has_memory_pattern(cmd_line, patterns) to check if any pattern string appears as a substring inside the full command line.

The bug: is_protected uses name == protected_set (comparing a string to a set, always False) instead of name in protected_set. Protected processes are never recognised, so the tool may kill systemd.

The lesson: == compares two values for equality. in tests membership in a collection or substring presence in a string. They are completely different operations and cannot be swapped.


💡 Fun fact: The in operator works on any iterable in Python, but its performance varies dramatically by collection type: x in list is O(n) (scans every element), while x in set and x in dict are O(1) average (hash lookup). For frequent membership checks on large collections, switching from a list to a set can be the difference between milliseconds and minutes.

⚠️ Watch out: Using == to test membership against a collection (like word == banned_words) always returns False because a string is never equal to a list — the code runs without error but your filter never triggers. Always use word in banned_words for containment.

🤔 Think about it: "free" in "free money" returns True as a substring check. But "free" in ["free money", "click here"] returns False — because it checks for exact list membership, not substrings. How does the type of the container change the meaning of in?

Learning objectives

  • Use ‘in’ to check membership in lists, sets, dicts, and substrings in strings
  • Use ‘not in’ for negation
  • Choose appropriate data structure for efficient membership checks

Key concepts

  • membership operators
  • in
  • not in
  • containment

Try it

Concept detail

‘in’ and ‘not in’ are membership operators. They work with:

  • Strings: ‘ello’ in ‘Hello’ → True (substring check)
  • Lists/tuples: 3 in [1, 2, 3] → True (linear search, O(n))
  • Sets: 3 in {1, 2, 3} → True (hash lookup, O(1) average)
  • Dicts: ‘key’ in {‘key’: ‘value’} → True (checks keys) ‘not in’ is the negation: 5 not in [1, 2, 3] → True. For performance with frequent lookups, use a set or dict (O(1)) instead of a list (O(n)).

Solution

def is_spam(message, banned_words):
    message_lower = message.lower()
    for word in banned_words:
        if word in message_lower:
            return True
    return False

def is_premium_user(user_id, premium_ids):
    return user_id in premium_ids

Tests

BANNED = ["buy now", "free money", "click here"]

def test_spam_detected():
    assert is_spam("Click here to win!", BANNED) == True

def test_no_spam():
    assert is_spam("Hello, how are you?", BANNED) == False

def test_spam_case_insensitive():
    assert is_spam("FREE MONEY available!", BANNED) == True

def test_premium_user():
    premiums = {101, 202, 303}
    assert is_premium_user(202, premiums) == True

def test_not_premium():
    premiums = {101, 202, 303}
    assert is_premium_user(999, premiums) == False

Resources