Python Operators: The `is` vs `==` Gotcha That Costs $5000
Production bug: payments over $5.
- Python operators are symbols that perform operations on values and variables
- Seven categories: arithmetic, comparison, logical, assignment, identity, membership, bitwise
- Arithmetic operators include / (float) and // (floor) — mixing them gives different results
- Comparison operators (== vs =) is the #1 bug: = assigns, == compares
- Identity operator
ischecks memory reference, not value — use == for value equality - Logical operators short-circuit:
andstops at first False,orstops at first True
Think of a Python operator like the buttons on a calculator. The numbers are your data, and the operator is the instruction that tells Python what to DO with them — add them, compare them, combine them. When you write 10 + 5, the + is the operator: it tells Python 'hey, add these two things together.' Without operators, you'd have data sitting around with no way to actually work with it — like having ingredients but no recipe.
Every program you'll ever write comes down to one thing: making decisions with data. Should this user get a discount? Is this password long enough? How much tax does this order cost? Every single one of those questions is answered using operators. They're the verbs of Python — they make things happen. If variables are the nouns (storing data), operators are what bring that data to life.
Before operators existed as a concept, you'd have to write entire custom functions just to add two numbers or check if one value was greater than another. Operators are shorthand that Python (and every other language) gives you so you can express complex logic in a single, readable character or symbol. They solve the problem of 'how do I actually DO something with my data?'
By the end of this article, you'll be able to use all seven categories of Python operators with confidence — arithmetic, comparison, logical, assignment, identity, membership, and bitwise. You'll know not just how to write them but WHY each one exists and when to reach for it. You'll also know the traps that catch beginners (and sometimes experienced devs), so you can sidestep them from day one.
Arithmetic Operators — Python as Your Calculator
Arithmetic operators are the ones you already know from maths class — addition, subtraction, multiplication, and division. But Python adds a few extras that are genuinely useful in real programming: floor division, modulus, and exponentiation.
Floor division (//) divides two numbers and throws away the decimal, giving you only the whole number part. Think of splitting a pizza: if 7 people share a pizza cut into 2, each person gets 3 slices — the remaining 1 slice doesn't magically split. That leftover is exactly what the modulus operator (%) gives you.
The modulus operator is one of the most underrated tools in programming. It's how you check if a number is even or odd, how you build cycling patterns, and how you keep a counter wrapping around a fixed range. The exponent operator () raises a number to a power — so 2 8 gives you 256, which matters a lot in computing, cryptography, and data sizing.
These seven arithmetic operators cover almost every mathematical operation you'll need in everyday Python programming.
5 / 2 gives 2.5 in Python 3, not 2. Use // when you need whole-number division. Floor division also matters in indexing — negative numbers round down (more negative), so (-7) // 3 gives -3, not -2. Always test boundary cases.Decimal from the decimal module. 0.1 + 0.2 is 0.30000000000000004 because of IEEE 754 representation. This is not a Python bug; it's how every CPU works./ always returns a float; // truncates toward negative infinity; % gives the remainder with the sign of the divisor.Decimal for money — floats will cost you real dollars.Comparison and Logical Operators — Teaching Python to Make Decisions
Comparison operators answer a yes-or-no question about your data. Is this value bigger than that one? Are these two values equal? Python evaluates the comparison and hands you back a boolean — either True or False. That True or False is then used by if-statements, while-loops, and everywhere else decisions are made.
There are six comparison operators: equal (==), not equal (!=), greater than (>), less than (<), greater than or equal to (>=), and less than or equal to (<=). Notice that equality uses TWO equals signs (==). One equals sign (=) is assignment — it stores a value. Two equals signs (==) is comparison — it asks a question.
Logical operators — and, or, not — let you combine multiple comparisons into a single, more powerful condition. Think of them like the connectors in everyday language. 'I'll go to the party IF it's on Saturday AND I'm not working.' That AND is exactly what Python's and operator does: both conditions must be True for the whole thing to be True.
or means at least one condition must be True. not flips a boolean — True becomes False and False becomes True. Together, these six comparison operators and three logical operators are the backbone of every conditional statement you'll ever write.
if user and user.is_active(), if user is None, Python never calls is_active(). That's good. But in if user.is_active() and user, you get AttributeError before the short-circuit can save you. Always put the cheap or guard check first.and and or don't return True/False — they return one of the operands. 0 or [] returns [], which is falsy. This trips up new devs when the result is used directly in a boolean context. Wrap with bool() if you need a strict boolean.and/or return operands, not booleans. If you need True/False, use bool() explicitly.Assignment Operators — Updating Values Without Repeating Yourself
You already know the basic assignment operator: the single equals sign (=). It stores a value into a variable. But Python gives you a set of shorthand assignment operators that combine assignment with an arithmetic operation in one step. These are called compound assignment operators, and they exist purely to save you from writing repetitive code.
Instead of writing score = score + 10, you can write score += 10. Python reads this as 'take the current value of score, add 10 to it, and store the result back in score.' Same result, less noise. Every arithmetic operator has a compound version: +=, -=, =, /=, //=, %=, and *=.
These aren't just cosmetic shortcuts. In long functions or loops, compound assignment operators make your code significantly easier to read because the variable name only appears once per line. Your eye immediately knows the variable is being updated, not reassigned from scratch. You'll see these constantly in real-world Python code, especially in loops that accumulate totals, counts, or running scores.
amount -= 1 in a multithreaded context can race — two threads may both read the same value and write back the same decremented result, losing a decrement. Use threading.Lock or an atomic type from multiprocessing.sharedctypes if you need thread-safe increments.:= is not compound assignment — it assigns and returns in the same expression. `if (x := get_data()) is None:` is a common pattern but can reduce readability when overused./= always produces a float; use //= for integer division in-place.Identity, Membership and Bitwise Operators — The Powerful Trio Beginners Skip
Most beginners learn arithmetic and comparison operators and stop there. But three more categories show up constantly in real Python code, and skipping them will leave you confused when you read someone else's code.
Identity operators (is and is not) check whether two variables point to the exact same object in memory — not just whether they have equal values. This is subtle but critical. Two variables can hold the same value but be completely different objects. Use == to compare values. Use is to check if something is literally None.
Membership operators (in and not in) check whether a value exists inside a collection like a list, string, or dictionary. They read almost like plain English: if 'admin' in user_roles is as clear as code gets. You'll use these constantly when filtering data or validating input.
Bitwise operators work on the individual binary digits (bits) of integers. They look strange at first but they're essential for low-level tasks like setting feature flags, working with permissions, or processing binary data. You won't need them every day, but you absolutely need to recognise them.
& vs logical and is a common confusion: 3 & 5 is 1 (bitwise), while 3 and 5 is 5 (logical, returning the last truthy operand). Using & for logical checks can produce silent data bugs — if permissions & 4: is a common bit test, but if permissions and 4: behaves completely differently.in for dictionaries checks keys, not values. 'key' in dict is O(1); 'value' in dict.values() is O(n). Choose wisely in performance-critical paths.is checks identity — use it only for None and singletons. == checks value — use that for everything else.in on a dict checks keys, not values. For bit manipulation, use &, |, ^ — never and/or.Operator Precedence and Associativity — The Silent Bug That Changes Your Results
When you write an expression with multiple operators, Python doesn't just evaluate left to right. It follows a strict order called operator precedence. This is the same PEMDAS you learned in school, but expanded to cover all operators.
Multiplication and division happen before addition and subtraction. 2 + 3 4 gives 14, not 20. Comparison operators (==, <, >) have lower precedence than arithmetic, so 3 + 4 > 2 3 is evaluated as (3 + 4) > (2 * 3), which is 7 > 6, True.
Logical operators have their own precedence: not > and > or. So not True or True and False is actually (not True) or (True and False), which is False or False, giving False. That's probably not what you meant. The safest rule: use parentheses when mixing logical or arithmetic operators. They cost nothing and prevent bugs.
Associativity determines the order when operators have the same precedence. Most operators are left-associative (evaluate left to right), but assignment and exponentiation are right-associative. a = b = c means a = (b = c). 2 3 2 is 2 (3 2) = 2 9 = 512, not (2 3) ** 2 = 64.
- Exponentiation (**) is highest among arithmetic operators and right-associative
- Multiplication, division, floor division, modulus (*, /, //, %) come before addition and subtraction
- Bitwise shifts (<<, >>) come after addition but before comparison
- Comparison operators (==, !=, <, >, <=, >=) come after arithmetic and bitwise shifts
- Logical not comes after comparison, and + or come after that
- Assignment (=, +=, etc.) is lowest — it happens last
price = base tax + discount but intended base (tax + discount). The bug caused $50,000 in undercharged orders over 3 months because no one noticed the discount was being added after tax instead of before.The $5000 Integer Cache Bug: When `is` Broke Our Payment Validation
is and == are interchangeable for integer comparisons, as they had read that Python caches small integers.is checks identity — and each arithmetic operation creates a new object. So amount is THRESHOLD was False even though the values matched.if payment.amount is cached_threshold: with if payment.amount == cached_threshold:.- Never use
isfor value comparison — it checks memory identity, not equality. ==is always safe for comparing primitive values and most objects.- Python's integer cache is an implementation detail, not a contract.
/ always returns a float; use // for integer division. Check operand types with type().'123' in [123] is False. Also check for mutable objects in sets/dicts.and / or returns something unexpected (not boolean)and and or return the last evaluated operand, not necessarily True/False. Use bool() to cast if you need a boolean.Key takeaways
= assigns, double == compares. This is the #1 Python bug/ always returns a float; // floors towards negative infinity. Use // for integer division and / when you need a decimal.% gives remainderis to check for None== for everything else.and/or short-circuit and return the last evaluated operandCommon mistakes to avoid
4 patternsUsing = instead of == in a condition (Assignment instead of Comparison)
Using == to compare with None instead of 'is'
Expecting integer division from '/' (forward slash)
Using 'and'/'or' where you meant &/| (logical vs bitwise)
Interview Questions on This Topic
What is the difference between the == operator and the is operator in Python? Give an example where they produce different results.
python
a = [1, 2, 3]
b = [1, 2, 3]
print(a == b) # True because values match
print(a is b) # False because they are two separate list objects
`
Note that Python caches small integers (-5 to 256), but this is an implementation detail. Never rely on it. Always use is for None and True/False singletons, and ==` for value comparisons.Frequently Asked Questions
That's Python Basics. Mark it forged?
5 min read · try the examples if you haven't