Operators and Expressions
Beginner⏱50 minutes📖14 min readLesson 4 of 10

Operators and Expressions

Learn how Python builds expressions from arithmetic, comparison, boolean and assignment operators, and why floor division, precedence and truthiness surprise beginners

A support ticket arrives with a screenshot, and the number on it is wrong. A customer bought three workshop seats at 10 euros each, with a 2 euro launch discount on every seat, and the receipt says 4 euros.

python
price = 10 seats = 3 total = price - 2 * seats print(total)

The developer read the line as "ten minus two, then times three". Python read it as "ten minus the result of two times three". Both readings feel obvious to the person who wrote them, and only one of them is what the interpreter does. The correct line is total = (price - 2) * seats, which charges 24 euros.

The bug is not a typo, and no library can rescue it. It is a missing model of how a line of code becomes a value: which symbols act on which neighbours, in what order, and what kind of result each step hands back. That model is the single most useful thing you can carry into every Python file you will read.

You will meet four families of operators, learn what each one returns, and see why division, comparison and boolean logic each hide one famous trap. Every example is checkable in a Python 3.15 REPL, and the practice questions reuse the same numbers so you can follow each step by hand.

Key terms

Operator
A symbol that asks Python to do something with the values beside it, such as + for addition or == for equality.
Operand
A value that an operator acts on. In 2 * seats, the operands are the int 2 and whatever object the name seats points at.
Expression
A piece of code that Python evaluates to produce one value, such as 2 + 3 or price - 2 * seats.
Evaluate
Work out the value of an expression by following the operator rules, from the innermost or highest precedence part outward.
Precedence
The ranking that decides which operator runs first when several appear in one expression, so multiplication beats addition.
Truthiness
The rule that decides whether an object counts as true or false in a condition. Empty collections and zero are falsy.
Short circuit
The habit of and and or to stop evaluating as soon as the answer is settled, without touching the remaining operand.
Identity
Whether two names point at the very same object in memory. The is operator tests identity, while == tests equal value.
Augmented assignment
A combined operator such as += or //= that reads a name, applies an operation and binds the name to the result.

1. Expressions, Operators and Operands

Start with the receipt line and take it apart. The right side of the = sign is an expression, and Python reduces it to a single value before the name on the left receives that value. Inside the expression, the symbols - and * are operators, and the values they work on are operands.

python
price = 10 seats = 3 total = price - 2 * seats # the expression on the right is evaluated first

An expression can be as small as one literal or as large as a page of nested calls. What matters is that every expression has a value and a type, and both are decided by the operators inside it. Arithmetic returns a number, comparison returns a bool, boolean logic returns one of its operands, and an assignment line changes a name rather than producing a reusable value. Keep those four result kinds in mind, because most beginner bugs come from expecting the wrong one.

Practice Question
How to answer

Multiple-choice question with 4 options. Select one option, then choose Check Answer.

A line of code reads `total = price - 2 * seats`. Which description correctly names the operators, the operands and the result?

2. Arithmetic: Seven Signs and Their Result Types

Arithmetic is the family you met first, but its result types are where the surprises live. Python has seven everyday arithmetic operators, and each one has a rule about the kind of object it returns.

Operator
Name
Example
Result
+
addition
10 + 3
13
-
subtraction
10 - 3
7
*
multiplication
10 * 3
30
/
true division
10 / 3
3.3333333333333335
//
floor division
10 // 3
3
%
remainder
10 % 3
1
**
exponentiation
10 ** 3
1000

Division always hands back a float

The forward slash performs true division, and true division always returns a float, even when the numbers divide evenly.

python
>>> 6 / 3, 4 / 2 (2.0, 2.0) >>> type(6 / 3) <class 'float'>

Floor division rounds down, not toward zero

The double slash performs floor division, and floor means the next lower whole number, not the number closer to zero. That difference appears the moment a negative value arrives.

python
>>> 7 // 2, -7 // 2, -7.0 // 2 (3, -4, -4.0)

For positive numbers the two ideas agree, which is why the trap waits until a refund, a temperature or a score below zero. There, -7 // 2 gives -4, because negative three point five floors down to negative four.

The remainder follows the divisor

The percent sign returns the remainder, and the sign of that remainder follows the divisor rather than the dividend.

python
>>> -7 % 3, 7 % -3, -7.5 % 2 (2, -2, 0.5)

The pair // and % always satisfies a == (a // b) * b + (a % b), even for negative numbers, and divmod hands you both parts in one call.

python
>>> divmod(47, 5), divmod(-7, 2) ((9, 2), (-4, 1)) >>> divmod(7.5, 2) (3.0, 1.5)

A bakery with 47 croissants and boxes of 5 fills 9 boxes and has 2 left over, which is exactly the (9, 2) pair. The choice between /, // and % is really a choice about the question you are asking, as the diagram shows.

100%
Description

A flowchart for the section The remainder follows the divisor, showing the path and decision points described in the surrounding text.

Fill in the Blanks
How to answer

Fill-in-the-blank exercise with 2 blanks. Type the missing words, then check your answer.

Complete the bill split so that the pair holds the full shares and the leftover euros.

bill = 47 people = 5 shares, leftover = blank(bill, people) each = bill blank people

Word Bank, drag words into the blanks above:

divmod
//
/
%
**
round

Powers group from the right

Exponentiation is right associative, which means a stack of powers is read from the top right downward.

python
>>> 2 ** 3 ** 2, (2 ** 3) ** 2 (512, 64) >>> -2 ** 2, (-2) ** 2 (-4, 4)

The first power is 2 ** 9, because Python groups 3 ** 2 first and raises 2 to that result. Unary minus binds more loosely than a power on its left, so read -2 ** 2 as the negative of two squared, not as negative two squared.

Mixed types promote, and bool is a number

When an int and a float meet, the result is a float. Since bool is a subclass of int, True also behaves as the number 1 in arithmetic.

python
>>> 1 + 2.5 3.5 >>> True + True 2

The plus and star signs also join or repeat sequences, which is your first taste of operator overloading. "ab" + "cd" is 'abcd', "ab" * 2 is 'abab', and [0] * 3 is [0, 0, 0]. Neither sign converts between kinds, so "ab" + 2 raises a TypeError rather than guessing what you meant.

ℹ️Note

📚 Did you know? bool is a subclass of int, so True == 1 is True and True + True is 2. The bool type was added on top of the existing integer world, and that arithmetic compatibility was kept on purpose.

Practice Question
How to answer

Multiple-choice question with 4 options. Select one option, then choose Check Answer.

A refund rule computes `-7 // 2` for a customer who is owed a negative adjustment. What does Python return, and why?

Practice Question
How to answer

Multiple-choice question with 2 options. Select one option, then choose Check Answer.

The expression `6 / 3` returns the int `2` in Python, because the division has no remainder.

Practice Question
How to answer

Multiple-choice question with 4 options. Select one option, then choose Check Answer.

What does the expression `2 ** 3 ** 2` evaluate to in Python?

3. Comparisons, Identity and Membership

Comparison operators ask a question and answer with a bool.

python
>>> 5 == 5, 5 != 5, 3 < 4 <= 4 (True, False, True)

The six signs are ==, !=, <, <=, > and >=, and they all return True or False. The double equals sign compares values, while a single equals sign assigns, and Python refuses to guess which one you meant in a condition.

Two comparisons can share one value

A chain such as 18 <= age <= 65 is not two separate expressions glued together. It means 18 <= age and age <= 65, and the middle value is evaluated exactly once.

python
>>> age = 30 >>> 18 <= age <= 65 True >>> 0 <= 100 <= 100 True

Identity asks a different question

The is operator tests whether two names point at the very same object, while == tests whether two objects have equal value.

python
>>> [] == [], [] is [] (True, False) >>> None is None True

Two empty lists are equal in value but are separate objects, so identity says no. Small integer objects may be cached inside one interpreter, but that is an implementation detail and never a rule you should build on. Use == for values and reserve is for None and other sentinels.

📌Important

Never compare numbers or strings with is, even when a quick test appears to work. The result can change between Python versions and between one run and the next, because object reuse is an internal choice rather than a language promise.

Membership asks whether a value is inside

The in and not in operators test membership in a string, list, tuple, set or dictionary.

python
>>> "a" in "cat" True >>> 3 in [1, 2, 3] True >>> "tea" not in ["coffee", "juice"] True

For text, membership checks a substring rather than a whole word, so "at" in "cat" is also true. For a dictionary, membership looks at keys by default.

Matching Question
How to answer

Matching exercise with 5 pairs. Match each item on the left with its answer on the right.

Match each operator to the question it answers.

==
Drop here
is
Drop here
in
Drop here
not in
Drop here
!=
Drop here

Drag answers from here:

Do these two values compare as equal?
Are these the very same object in memory?
Does this collection contain the value?
Is the value absent from the collection?
Do these two values differ?
Practice Question
How to answer

Multiple-choice question with 4 options. Select one option, then choose Check Answer.

A gym check uses `18 <= age <= 65`. When `age` is 30, how does Python evaluate that expression?

Practice Question
How to answer

Multiple-choice question with 2 options. Select one option, then choose Check Answer.

The check `[] is []` returns `True`, because the two empty lists hold the same contents.

4. Boolean Operators and Truthiness

The words and, or and not combine conditions. Before they can do that, Python must decide which values count as true, and that decision is called truthiness.

python
>>> bool(0), bool(""), bool([]), bool(None) (False, False, False, False) >>> bool(1), bool("x"), bool([0]) (True, True, True)

None, False, numeric zero and empty collections are falsy. Almost everything else is truthy, including the text "False" and the list [0], because a non-empty container is true regardless of what it contains.

and and or return an operand

This is the point where the intuition from other languages fails. The operators and and or short circuit, and they hand back one of their operands rather than a converted bool.

python
>>> 3 and 4 4 >>> 3 or 4 3 >>> 0 or "x" 'x' >>> [] or 5 5

and returns the first falsy operand, or the last operand if every value is truthy. or returns the first truthy operand, or the last operand if every value is falsy. Only not always returns a real bool.

python
>>> not 3 False >>> not [] True
ℹ️Note

📚 Did you know? The operand return rule is what makes name = user or "guest" work as a default. When user is empty, or skips it and hands back the text, so a falsy value never reaches the name.

Short circuit stops the work

Short circuit means the second operand may never be evaluated at all. This is both a performance detail and a safety feature.

python
>>> 0 and (1 / 0) 0 >>> 3 or (1 / 0) 3

Neither line raises a ZeroDivisionError, because the answer was already settled. Swap the order and the division runs, which is why guards such as if items and items[0] are safe while the reverse order can fail.

100%
Description

A flowchart for the section Short circuit stops the work, showing the path and decision points described in the surrounding text.

not binds more loosely than a comparison

The word not sits below comparison in the precedence table, so not a == b means not (a == b).

python
>>> a, b = 1, 2 >>> not a == b True >>> (not a) == b False

The first line asks whether the equality failed, which is true. The second line asks whether False equals 2, which is false. Add parentheses when the sentence in your head needs them.

Practice Question
How to answer

Multiple-choice question with 4 options. Select one option, then choose Check Answer.

A REPL evaluates `3 and 4` and then `0 or "x"`. Which pair of results is printed?

Practice Question
How to answer

Multiple-choice question with 2 options. Select one option, then choose Check Answer.

The empty list `[]` is falsy in Python, so the expression `[] or 5` returns `5`.

5. Assignment, Augmented Assignment and the Walrus

A single equals sign binds a name to a value. A condition needs a comparison, so writing if x = 5: is a syntax error rather than a quiet assignment.

python
x = 10 # assignment x == 10 # comparison, returns True

Augmented assignment combines a calculation with a rebinding, and the shorthand covers every arithmetic and bitwise sign.

python
x = 10 x += 5 # 15 x -= 3 # 12 x *= 2 # 24 x /= 4 # 6.0 x //= 2 # 3.0 x %= 2 # 1.0 x **= 3 # 1.0

The /= line is the one to watch, because true division turns an int name into a float. Every later line then works on a float, which is why the state diagram marks the type change as a real event.

100%
Description

A state diagram for the section 5. Assignment, Augmented Assignment and the Walrus, showing the states and transitions described in the surrounding text.

Augmented assignment usually rebinds a name to a new object, but mutable objects are the exception. For a list, += extends the existing list in place instead of building a fresh one, and that difference matters when two names point at the same list.

The conditional expression and the walrus

A conditional expression chooses between two values: `label = "pass" if score

= 60 else "retry"`. Read it as this value if the condition holds, otherwise that value, and note that it is an expression rather than a statement.

The walrus operator := assigns a name inside a larger expression, which avoids evaluating the same call twice.

python
while (line := file.readline()): print(line.rstrip())

The parentheses are required in most mixed contexts, and the operator is best kept for a read that feeds a test. If a line needs a comment to explain the binding, split it into two ordinary statements instead.

⚠️Warning

Do not use the walrus to make a line shorter at the cost of clarity. A name created inside a condition lives on after the condition, so a reader has to track it through the rest of the block.

Practice Question
How to answer

Multiple-choice question with 4 options. Select one option, then choose Check Answer.

A counter starts as `count = 10`, which is an int. After the line `count /= 2` runs, what are the value and the type?

6. Precedence, Parentheses and the Bug From the Till

Return to the receipt. Python groups 2 * seats before the subtraction because multiplication outranks subtraction, and the fix is a pair of parentheses. Precedence is the full ranking that decides this order, and it is longer than the school acronym suggests. PEP 8 also asks for single spaces around binary operators, because crowded signs slow a reader down.

Level
Operators
Meaning
1
( )
parentheses, evaluated first
2
**
power, grouping right to left
3
+x, -x, ~x
unary signs
4
*, @, /, //, %
multiply and divide
5
+, -
add and subtract
6
<< >> & ^ |
bit shifts and bitwise work
7
comparisons, in, is
tests, which chain
8
not
boolean negation
9
and
boolean AND
10
or
boolean OR
11
if ... else
conditional expression

The school acronym covers levels 2 to 5 and then stops, which is why it cannot explain not a == b or a chained comparison. Learn the shape of the table, and reach for parentheses whenever a reader would need the table to follow you.

python
>>> 2 + 3 * 4 14 >>> (2 + 3) * 4 20 >>> 2 ** 3 * 4 32 >>> -2 ** 2 -4

The sequence diagram follows the first two lines through the same four numbers. The tree changes, and the answer changes with it.

100%
Description

A sequence diagram for the section 6. Precedence, Parentheses and the Bug From the Till, showing the order of messages and replies described in the surrounding text.

Order the steps below to rebuild the buggy line, then compare the order with the fix. The first card names the target, and the last card shows what the receipt prints.

Ordering Question
How to answer

Ordering exercise with 4 items. Move them into the correct order, then check your answer.

Order the evaluation steps for `total = 10 - 2 * 3`.

Read the name total on the left
Evaluate 2 * 3 because multiplication outranks subtraction
Subtract 6 from 10
Bind total to 4
💡Tip

Parentheses are free at run time and priceless during review. When a line mixes three or more operators, or when a colleague might read it two ways, add the brackets that state your intent rather than trusting the table.

Worked examples with real numbers

These four calculations cover billing, science and scores. Type them into a REPL and check each printed line.

python
>>> bill = 45.50 >>> tip = bill * (15 / 100) >>> tip 6.825 >>> total = bill + tip >>> f"{total:.2f}" '52.33'

The tip is a float because 15 / 100 is true division, and the format spec rounds only the display to two places. The temperature conversion of 25 gives (25 * 9 / 5) + 32, which is 77.0, and the reverse direction gives 25.0 back.

python
>>> number = 7 >>> number % 2 == 0 False >>> weight, height = 70, 1.75 >>> round(weight / height ** 2, 1) 22.9

The even check relies on the remainder, and the body mass index relies on the power running before the division.

7. Modern Python and the Operator Landscape

2026 Updates (as of November 2026)

ℹ️Note

What changed recently, and what did not. Every line below was checked against a primary source in November 2026:

  • Python 3.15.2 is the current stable release, shipped on 2026-10-25 after 3.15.0 on 2026-10-09. The operator syntax here is unchanged in 3.15.
  • Python 3.10 reached end of life on 2026-10-01, so a beginner should start a project on a supported series such as 3.15.
  • Error messages keep improving. Python 3.15 suggests the likely fix for common mistakes, for example it points from [1, 2, 3].push(4) to .append, which shortens the search for a wrong name.
ℹ️Note

📚 Did you know? The @ sign is matrix multiplication, not a decoration for email addresses. It was added in Python 3.5 for libraries that work with grids of numbers, and [1, 2] @ [3, 4] on plain lists raises a TypeError because list objects never learned that operator.

Bitwise operators are a short aside. They work on the binary digits of ints: & is AND, | is OR, ^ is XOR, ~ flips bits, and << and >> shift.

python
>>> 5 & 3, 5 | 3, 5 ^ 3 (1, 7, 6) >>> ~5, 1 << 3, 16 >> 2 (-6, 8, 4)

Real-World Case Studies

Operator rules look academic until a codebase reaches a scale where every expression runs billions of times. Three public engineering stories show why the details in this lesson matter in production.

Meta, Instagram and Threads. Meta's engineering blog described Python in June 2026 as its most used language, naming the Instagram and Threads backends and the PyTorch origins of its machine learning work. At that scale, a guard such as a membership test or a chained comparison sits on a hot path, and the difference between an operand and a bool can change what a feature flag does.

Netflix. The Netflix Tech Blog described Python across the full content lifecycle in April 2019, including tooling for the Open Connect CDN. Arithmetic and comparison expressions decide encoding choices and capacity checks there, so a floor division that rounds the wrong way is a real operational risk rather than a quiz answer.

Dropbox. Dropbox described one of the largest Python 2 to Python 3 migrations on its engineering blog, and later reported type checking close to four million lines. A migration at that size has to preserve the exact result type of every arithmetic expression, which is why the difference between / and // belongs in every review checklist.

📌Important

Large teams survive these traps with tests and type checkers, not with memory. A test that pins the expected value and type of a calculation catches a precedence change before a customer sees a four euro receipt.

Practice Questions

Answer these before moving on. Each stem stands on its own, so a review session can show it without the page. The inline questions count too, and every id stays stable for scheduling.

Practice Question
How to answer

Multiple-choice question with 4 options. Select one option, then choose Check Answer.

A script runs `seats = int(7.9)`. Which value is stored, and which rule explains it?

Practice Question
How to answer

Multiple-choice question with 2 options. Select one option, then choose Check Answer.

The expression `0.1 + 0.2 == 0.3` evaluates to `True` in Python, because arithmetic on small decimal numbers is exact.

What Comes Next

You can now read the receipt bug, explain the wrong total and repair it with parentheses. The next lesson puts these expressions to work in conditions, where a comparison or a truthy value decides which branch runs. Before that, the video below is a parallel reference, and its operators chapter restates this material in a second voice.

A friendly parallel reference for operators: watch the arithmetic and condition chapters after finishing this lessonWatch on YouTube
Description

A video walkthrough that supports the section What Comes Next and repeats its main ideas in a second voice.

✅Success

Key Takeaways:

  1. An expression is a piece of code that evaluates to one value, and its operators decide both the value and the result type.
  2. / is true division and always returns a float, even for 6 / 3, which gives 2.0.
  3. // floors toward negative infinity, so -7 // 2 is -4, while % follows the sign of the divisor.
  4. divmod(a, b) returns the quotient and remainder pair, so divmod(47, 5) is (9, 2).
  5. ** groups right to left and binds tighter than unary minus, so 2 ** 3 ** 2 is 512 and -2 ** 2 is -4.
  6. Comparison chains mean and, so 18 <= age <= 65 tests both bounds and evaluates the middle value once.
  7. == compares values while is compares identity, and None is the one case where is is the clear choice.
  8. and and or short circuit and return an operand, so 3 and 4 is 4 and [] or 5 is 5.
  9. Augmented assignment rebinds a name, and /= turns an int into a float, which changes every later calculation.
  10. Parentheses beat every precedence argument, and they turn a four euro receipt bug into a 24 euro fix.

References

Every factual claim links to its source, with the access date printed so the source can be rechecked.

  1. [1]Built-in typesDocumentation

    Python Software Foundation · Accessed 2026-11-04

  2. Python Software Foundation · Accessed 2026-11-04

  3. Python Software Foundation · Accessed 2026-11-04

  4. [4]Expressions referenceDocumentation

    Python Software Foundation · Accessed 2026-11-04

  5. Python Software Foundation · Accessed 2026-11-04

  6. Python Software Foundation · Accessed 2026-11-04

  7. Python Software Foundation · Accessed 2026-11-04

Progress40%