---
title: 'Operators and Expressions'
source: 'https://academia.sh/en/courses/programming-fundamentals/operators-and-expressions'
course: 'Programming Fundamentals'
language: en
updated: '2026-08-17T18:08:26+00:00'
license: 'CC BY-SA 4.0'
---

# Operators and Expressions

Arithmetic, comparison, and logical operators; precedence, associativity, and short-circuit evaluation.

The first lesson gave an example of a logic error: the expression
`measurement_1 + measurement_2 / 2` did not give the expected average. The error
came from not knowing in which order the operators are applied.

This lesson defines those rules. The rules repeat across languages with small
differences; what is common is that precedence agrees with the conventions of
mathematics.

## Arithmetic Operators

| Operator | Meaning | Example | Result |
|---|---|---|---|
| `+` | addition | `12 + 18` | 30 |
| `-` | subtraction | `18 - 12` | 6 |
| `*` | multiplication | `6 * 7` | 42 |
| `/` | real division | `7 / 2` | 3.5 |
| `//` | integer division | `7 // 2` | 3 |
| `%` | remainder | `7 % 2` | 1 |
| `**` | exponentiation | `2 ** 10` | 1024 |

The remainder operator is used more often than it appears: whether a number is even
(`n % 2 == 0`), a counter cycling at fixed intervals, and distributing values across
a fixed number of buckets are all written with this operator.

## Comparison Operators

Comparison operators produce a boolean value: `==`, `!=`, `<`, `>`, `<=`, `>=`.

Writing the equality test as `==` is meant to distinguish it from assignment,
written `=`. Confusing the two produces a program that is valid but wrong in some
languages; for this reason many languages forbid assignment inside a condition.

The distinction established in the previous lesson holds here too: `==` tests
content equality, `is` (or its counterpart) tests whether it is the same object.

Some languages allow comparisons to be chained:

```python
measurement = 12
print(0 < measurement < 100)          # True  — two comparisons and a logical 'and'
```

This notation is readable but not universal; in most languages the same expression
gives a result different from what is expected, because `0 < measurement` is
computed first and its result is then compared with `100`.

## Logical Operators

Three logical operators combine conditions:

| $a$ | $b$ | `a and b` | `a or b` | `not a` |
|---|---|---|---|---|
| false | false | false | false | true |
| false | true | false | true | true |
| true | false | false | true | false |
| true | true | true | true | false |

This table is identical to the bit-level AND/OR tables from the previous course. The
difference is that these operators work on the entire expression, not on individual
bits.

## Short-Circuit Evaluation

Logical operators have a distinguishing behavior: once the result is determined, the
right side is **never evaluated**.

- In the `and` operator, if the left side is false, the result is false; the right
  side is not examined.
- In the `or` operator, if the left side is true, the result is true; the right side
  is not examined.

This is not merely a speed optimization, it is a programming tool: the condition
required for the right side to run safely is secured by writing it on the left.

```python
divisor = 0

# The division never happens because the left side is false; no error occurs.
if divisor != 0 and 10 / divisor > 1:
    print("large")
else:
    print("condition not met")      # condition not met

measurements = []

# The first element is not accessed because the left side is true.
if len(measurements) == 0 or measurements[0] > 10:
    print("empty or first measurement large")   # empty or first measurement large
```

If the order of the two conditions is swapped, the programs raise a runtime error.
The order of conditions is therefore a matter of correctness, not style.

## Precedence and Associativity

**Precedence** determines which of two different operators is applied first;
**associativity** determines which direction operators of the same precedence group
in.

The commonly used precedence order, from highest to lowest:

| Order | Operators |
|---|---|
| 1 | `()` grouping |
| 2 | `**` exponentiation |
| 3 | unary `-` (sign) |
| 4 | `*`, `/`, `//`, `%` |
| 5 | `+`, `-` |
| 6 | comparisons |
| 7 | `not` |
| 8 | `and` |
| 9 | `or` |

```python
print(2 + 3 * 4)          # 14   — multiplication first
print((2 + 3) * 4)        # 20   — grouping changes precedence
print(2 ** 3 ** 2)        # 512  — exponentiation right to left: 2 ** (3 ** 2)
print(-2 ** 2)            # -4   — exponentiation before unary minus: -(2 ** 2)
print(10 - 3 - 2)         # 5    — subtraction left to right: (10 - 3) - 2
print(True or False and False)   # True — 'and' first
```

The logic error from the first lesson is explained by this table: in the expression
`measurement_1 + measurement_2 / 2`, division is at order four and addition at order
five; division is performed first.

Practical rule: knowing the precedence rules is necessary, but relying on the reader
knowing them is not advisable. Using parentheses where confusion is possible does not
substitute for knowing the rule — it makes the rule visible.

## Compound Assignment

Updating a variable based on its own value is written so often that languages offer
a short notation for it:

```python
total = 0
total = total + 12       # explicit form
total += 18               # compound assignment: same operation
print(total)              # 30

counter = 10
counter -= 1                 # 9
counter *= 2                 # 18
counter //= 5                # 3
print(counter)                # 3
```

Compound assignment is not an operator but a notational shorthand: `a += b` means
`a = a + b`. The shorthand has two benefits — the variable name is written once
(lowering the chance of assigning to the wrong name), and the reader sees at a
glance that the update is on the same variable.

This equivalence thins out for mutable types: in some languages, compound
assignment updates the existing object in place instead of producing a new one. In a
shared list this difference produces observable consequences; the distinction is an
extension of the rule established around immutability.

One warning: compound assignment is also a statement, not an expression. It has no
value; it cannot be placed inside another expression.

## Same Operator, Different Meaning

An operator's meaning depends on the types it is applied to:

```python
print(3 + 4)              # 7        — numeric addition
print("3" + "4")          # 34       — string concatenation
print([1, 2] + [3])       # [1, 2, 3] — list concatenation
print("ab" * 3)           # ababab   — repetition
```

The same symbol performing a different operation across different types is called
**operator overloading**. It provides convenience; in exchange, code that assumes
the wrong type can silently produce an unexpected result. A `+` operation performed
without knowing whether a value taken from the user is a number or a string is the
typical example of this.

This connects directly to the next lesson's subject: what happens when a value's
type differs from what is expected?

## Summary

- Among the arithmetic operators, integer division and remainder are used
  frequently in numeric problems.
- Comparison operators produce a boolean value; `==` tests content equality and is
  not assignment.
- `and`, `or`, and `not` combine conditions; their truth tables are identical to
  their bit-level counterparts.
- In short-circuit evaluation the right side does not run once the result is
  determined; the order of conditions affects correctness.
- Precedence determines which operator is applied first, associativity determines
  how operators of the same precedence group; exponentiation associates right to
  left.
- The same operator can carry different meanings across different types.

## Next Step

What happens when different types meet in an expression? Can a string be added to a
number, how is a real number converted to an integer, and what is lost in these
conversions? The next lesson takes up type conversion and the consequences of a
lossy conversion.
