AlgoMaster Logo

Operators

High Priority22 min readUpdated June 6, 2026
Listen to this chapter
Unlock Audio

Operators are the small symbols that make Python actually compute things: adding cart totals, comparing prices, checking whether a product is in stock, combining boolean conditions. This lesson covers every operator you'll use day-to-day, the rules Python follows when several appear in the same expression, and a few sharp edges that trip up beginners.

Arithmetic Operators

These do the same thing they did in school, with two extras worth knowing about: floor division and exponentiation.

OperatorNameExampleResult
+Addition19.99 + 4.9924.98
-Subtraction100 - 19.9980.01
*Multiplication19.99 * 359.97
/True division10 / 33.3333333333333335
//Floor division10 // 33
%Modulo (remainder)10 % 31
**Exponentiation2 ** 101024

Here they are working on a small cart:

Two things deserve a closer look: / versus //, and what % actually does.

/ always returns a float, even when the numbers divide evenly. 10 / 2 is 5.0, not 5. If you want an integer result, use //, which discards the fractional part and rounds toward negative infinity:

That last result surprises people. -10 // 3 is -4, not -3, because floor division rounds down (toward negative infinity), not toward zero. If you want truncation toward zero, use int(-10 / 3) instead, which gives -3.

% returns the remainder after division. It's useful for splitting items into groups or detecting "every Nth" events:

** is exponentiation. 2 ** 10 is 1024, 9 ** 0.5 is 3.0. It also works with negative exponents to give fractions: 2 ** -1 is 0.5.

Comparison Operators

Comparison operators return True or False. You use them everywhere: filtering products by price, checking stock, deciding which orders qualify for free shipping.

OperatorMeaningExampleResult
==Equal to19.99 == 19.99True
!=Not equal to19.99 != 24.99True
<Less than5 < 10True
<=Less than or equal5 <= 5True
>Greater than10 > 5True
>=Greater than or equal10 >= 10True

A common beginner mistake is using = (assignment) when you meant == (comparison). Python will refuse to run code like if cart_total = 50: and raise a SyntaxError, which is helpful. The two symbols do completely different things: = puts a value into a name, == asks whether two values are equal.

Comparisons also work on strings (lexicographic order) and other types, but mixing types you can't compare raises an error:

String comparison goes character by character using Unicode code points, so "apple" comes before "banana". Comparing a number to a string makes no sense to Python and raises TypeError.

Chained Comparisons

Python has a feature most other languages don't: you can chain comparison operators in a single expression and Python evaluates them mathematically.

20 < price < 100 reads exactly like math notation and means 20 < price and price < 100. Python evaluates price once and combines both comparisons.

Here's the flow Python actually follows when it sees a chained comparison:

The key insight is that price is computed exactly once and then reused for both comparisons. If the first check fails, Python doesn't even bother evaluating the second one, which is the same short-circuit behavior and uses everywhere else.

You can chain as many as you want, and they can mix operators:

The second one means "1 < rating AND rating < 5 AND 5 != 0", which is True because all three are true.

Without chaining, you'd write the awkward version:

That works fine, but the chained form is more readable and slightly faster because price is evaluated only once.

Logical Operators

Logical operators combine boolean values. Python uses words (and, or, not) instead of symbols like && and ||.

OperatorMeaningExampleResult
andTrue if both are trueTrue and FalseFalse
orTrue if either is trueTrue or FalseTrue
notInverts the valuenot TrueFalse

Here's a cart check that combines two conditions:

Two behaviors are worth pinning down: short-circuit evaluation and the actual value these operators return.

Short-Circuit Evaluation

and and or stop evaluating as soon as the answer is known.

  • False and X is always False, so Python never evaluates X.
  • True or X is always True, so Python never evaluates X.

This lets you guard against errors:

If discount_code is empty, the first half is False and Python skips the second half entirely. Without short-circuiting, calling .startswith("SAVE") on a value you haven't validated could be a bug source.

This diagram shows how or decides whether to evaluate its right operand, and what it actually returns (which is one of the operands, not a plain True or False):

and mirrors this exactly, just with the test flipped: it stops on the first falsy operand and returns it, otherwise it returns the right operand. That's why "" or "Guest" returns "Guest" (left is falsy, so it falls through) and "Alex" and "alex@example.com" returns the email (left is truthy, so and keeps going).

What and and or Actually Return

Here's a subtle point: and and or don't return True or False directly. They return one of the operands.

  • a and b returns a if a is falsy, otherwise b.
  • a or b returns a if a is truthy, otherwise b.

0 or 19.99 returns 19.99 because 0 is falsy. "" or "Guest" falls back to "Guest" for the same reason, which is a common idiom for default values. "Alex" and "alex@example.com" returns the second value because the first is truthy and and keeps going.

That's why you often see code like name = user_name or "Guest" in Python: it uses the actual value when it exists and falls back when it doesn't.

not is simpler. It always returns a real True or False:

not "" is True because the empty string is falsy. not 19.99 is False because any non-zero number is truthy.

Identity vs Equality: is vs ==

== asks "are these values equal?". is asks "are these the same object in memory?". They look similar but mean different things.

cart_a and cart_b have equal contents, so == is True. They're two separate lists in memory though, so is is False. cart_c was assigned from cart_a, so both names point to the exact same list, and is is True.

The rule of thumb: use == for value comparison, and reserve is for comparing with None, True, or False:

The official Python style guide (PEP 8) says to compare with None using is and is not, not ==. There's only ever one None object in a running Python program, so identity is the right test.

is not is the negated form. selected_coupon is not None means "the coupon exists".

A trap that catches everyone eventually: small integers and short strings are often interned (reused) by the interpreter, which makes is accidentally work for them in some cases and not others:

This is an implementation detail of CPython. Don't rely on it. Use == for values and is only for singletons.

Membership Operators: in and not in

in checks whether a value appears in a collection. It works for strings, lists, tuples, sets, dictionaries, and other iterables.

For strings, in checks substring containment:

For dictionaries, in checks the keys, not the values:

12 is a value in the dictionary, but in only looks at keys, so it returns False. If you actually want to search values, use 12 in stock.values().

Bitwise Operators

Bitwise operators work on the binary representation of integers. You won't reach for them often in everyday application code, but they show up in low-level work: feature flags, permission bits, color manipulation, hash tricks.

OperatorNameExampleResult
&AND0b1100 & 0b10100b1000 (8)
|OR0b1100 | 0b10100b1110 (14)
^XOR0b1100 ^ 0b10100b0110 (6)
~NOT~0b1100-13
<<Left shift1 << 416
>>Right shift16 >> 24

A practical case: storing customer notification preferences as flags. Each preference is one bit.

| combines flags. & checks whether a flag is set. The result of preferences & EMAIL is either 0 (false) or the flag's value (truthy), which is why bool(...) produces the right answer.

<< and >> shift bits left and right. Left-shifting by n is equivalent to multiplying by 2 ** n, right-shifting divides by 2 ** n (floor):

~ flips every bit. For a Python integer, the result is -(x + 1) because of how negative numbers are represented in two's complement. ~5 is -6, ~0 is -1.

These operators only work on integers. Using them on floats raises TypeError. If you don't need bit-level work, you can comfortably skip them for now.

Assignment and Augmented Assignment

You already know =: it binds a value to a name. The augmented assignment operators combine an arithmetic or bitwise operator with assignment.

OperatorEquivalent toExample
+=x = x + ytotal += price
-=x = x - ystock -= 1
*=x = x * yprice *= 1.1
/=x = x / yshare /= 4
//=x = x // ygroups //= 5
%=x = x % yindex %= 10
**=x = x ** yvalue **= 2
&=, |=, ^=, <<=, >>=Bitwise variantsflags |= ADMIN

Building a cart total step by step:

For numbers and strings (which are immutable), x += y and x = x + y produce the same result. For mutable types like lists, there's a subtle difference: += modifies the existing list in place, while x = x + y creates a new list.

Both names see the new item because += on a list mutates the original list, and cart_b points to the same one. Compare with this version:

cart_a + ["USB Cable"] builds a new list and rebinds cart_a to it. cart_b still points to the original, so it doesn't change. This difference matters a lot once you start passing lists into functions.

Operator Precedence

When an expression mixes operators, Python evaluates them in a specific order. Higher precedence binds tighter, meaning that operator runs first.

PrecedenceOperatorsNotes
Highest**Right-to-left associative
+x, -x, ~xUnary plus, minus, bitwise NOT
*, /, //, %Multiplicative
+, -Additive
<<, >>Bitwise shifts
&Bitwise AND
^Bitwise XOR
|Bitwise OR
==, !=, <, <=, >, >=, is, is not, in, not inAll comparison and membership operators
notLogical NOT
andLogical AND
LowestorLogical OR

The full table in the official docs has a few more rows for things you'll meet later (lambda, conditional expressions), but the above covers everything in this lesson.

Two quick examples:

In 2 + 3 * 4, the multiplication runs first (higher precedence), so it's 2 + 12. Parentheses force the addition first.

Mixing arithmetic, comparison, and logical operators in one line:

Comparison operators bind tighter than and, so Python evaluates price > 20 (True) and stock > 0 (True) first, then combines them with and. You don't need parentheses, but adding them never hurts readability:

One detail that confuses people: ** is right-associative.

2 ** 3 ** 2 means 2 ** (3 ** 2), which is 2 ** 9 = 512, not (2 ** 3) ** 2 = 64. If you're nesting exponentiation, use parentheses to be explicit.

When you're unsure, parentheses are free. They cost nothing at runtime and make intent obvious.

Quiz

Operators Quiz

10 quizzes