This post covers the core syntax every Python program uses: variables, primitive types, operators, conditionals, and loops. Python's defining visual feature — meaningful indentation — is introduced and explained. By the end, you can write any control-flow logic you'd expect from a beginner book.

Series map: 00 Setup → 01 Syntax (this post) → 02 Data Structures → 03 Functions & Modules → 04 OOP → 05 Files & Exceptions → (future).


Learning Outcome

  • Declare variables and understand dynamic typing.
  • Use the six core primitive types: int, float, bool, str, None, bytes.
  • Use arithmetic, comparison, logical, and assignment operators.
  • Write if/elif/else, for, and while blocks.
  • Understand indentation as syntax (not decoration).
  • Use break, continue, and else on loops.

Chapter 1 — Variables and dynamic typing

Terminology

  • Variable — a name bound to a value.
  • Dynamic typing — variable types are checked at runtime, not declaration time.
  • Type hint — optional annotation (x: int = 5) — ignored at runtime, used by tools.
  • Mutable / immutable — whether a value can be changed in place.

Assignment

1
2
3
4
5
6
x = 5            # int
pi = 3.14159 # float
name = "Ada" # str
is_ready = True # bool
nothing = None # NoneType

No type declaration required. You can rebind to a different type:

1
2
3
x = 5
x = "now a string" # legal in Python
1
2
3
x: int = 5
name: str = "Ada"

These are hints — Python ignores them at runtime. Tools like mypy, pyright, and your IDE use them for static analysis. Use them in real code; skip them in throwaway scripts.

Trick: if you print(type(x)), Python tells you the runtime type. Great for debugging "wait, why is this a string?" surprises.


Chapter 2 — Primitive types

Type Example Note
int 42, -7, 0, 10_000 Arbitrary precision — no overflow! 2**100 works fine.
float 3.14, 1e-5, 2.0 IEEE 754 double.
bool True, False A subclass of int: True == 1, False == 0.
str "hello", 'world', """multi-line""" Immutable, Unicode by default.
None None The "no value" singleton.
bytes b"raw", b"\x00\xff" Immutable sequence of 8-bit values.

String highlights

1
2
3
4
5
6
7
8
9
10
s = "Hello"
len(s) # 5
s.upper() # "HELLO"
s[0] # "H"
s[-1] # "o" (negative = from end)
s[1:4] # "ell" (slice)
"He" in s # True
s + " World" # "Hello World"
s * 3 # "HelloHelloHello"

f-strings (the preferred way to format)

1
2
3
4
5
6
7
8
name = "Ada"
age = 30
f"{name} is {age}" # "Ada is 30"
f"{age * 2}" # "60"
f"{3.14159:.2f}" # "3.14" (2 decimal places)
f"{42:>5}" # " 42" (right-align width 5)
f"{name=}" # "name='Ada'" (debug form, Python 3.8+)

Trick: the {var=} debug form is the single most-used Python 3.8+ feature. f"{user_id=} {total=}" gives "user_id=42 total=99.50" — perfect for logging.


Chapter 3 — Operators

Arithmetic

Op Meaning Example
+ add 3 + 4 → 7
- subtract 7 - 2 → 5
* multiply 3 * 4 → 12
/ true divide 7 / 2 → 3.5
// floor divide 7 // 2 → 3
% modulo 7 % 3 → 1
** power 2 ** 10 → 1024

Comparison

==, !=, <, >, <=, >= — return bool. Python supports chained comparison:

1
2
3
if 0 < x < 10:           # legal, means 0 < x AND x < 10
...

Logical

and, or, not. They short-circuit:

1
2
3
4
x and y    # if x is falsy, returns x; else returns y
x or y # if x is truthy, returns x; else returns y
not x # True if x is falsy

Falsy values: False, 0, 0.0, "", [], {}, (), None. Everything else is truthy.

Assignment shorthand

1
2
3
4
5
x += 1     # same as x = x + 1
x -= 2
x *= 3
x //= 2

Identity vs equality

1
2
3
4
5
6
a = [1, 2, 3]
b = [1, 2, 3]
a == b # True (same content)
a is b # False (different objects)
a is None # idiomatic way to check for None — use `is`, not `==`

Chapter 4 — Indentation is syntax

This is the rule that shocks beginners coming from C-family languages. Python uses indentation (not {} or begin/end) to define blocks.

1
2
3
4
5
if x > 0:
print("positive") # this line is inside the if
print("still inside") # this too
print("outside the if") # this is after

Rules:

  • All lines in the same block must have exactly the same indentation.
  • Standard is 4 spaces per level (PEP 8).
  • Never mix tabs and spaces. Most editors auto-convert.
  • A colon : introduces a new block (after if, for, while, def, class, try, etc.).

Where I got stuck: I once spent 30 minutes debugging a script that "just didn't run the loop". The culprit: a tab character on one line where the rest used spaces. Python silently disagrees about whether they're equal. Modern editors highlight whitespace; turn it on.


Chapter 5 — Conditionals

1
2
3
4
5
6
7
8
9
10
11
age = int(input("Age: "))

if age < 13:
print("child")
elif age < 20:
print("teen")
elif age < 65:
print("adult")
else:
print("senior")

Ternary expression

1
2
status = "adult" if age >= 18 else "minor"

Read it left-to-right: "value, if condition, else alternative".

match (Python 3.10+, like switch but better)

1
2
3
4
5
6
7
8
match command:
case "start":
print("starting")
case "stop" | "halt":
print("stopping")
case _:
print("unknown")

The _ is a catch-all. match also supports pattern destructuring — covered in a future advanced post.


Chapter 6 — Loops

for loop

Python's for always iterates over an iterable (sequence, generator, etc.). It is not the C-style for(i=0; i<10; i++).

1
2
3
4
5
6
7
8
9
10
11
12
for fruit in ["apple", "banana", "cherry"]:
print(fruit)

for i in range(5): # 0, 1, 2, 3, 4
print(i)

for i in range(2, 8): # 2..7
print(i)

for i in range(0, 20, 3): # 0, 3, 6, 9, 12, 15, 18 (step=3)
print(i)

enumerate (index + value)

1
2
3
4
5
6
for i, name in enumerate(["Ada", "Bob", "Cy"]):
print(i, name)
# 0 Ada
# 1 Bob
# 2 Cy

zip (parallel iteration)

1
2
3
4
5
names = ["Ada", "Bob"]
ages = [30, 25]
for name, age in zip(names, ages):
print(name, age)

while loop

1
2
3
4
5
n = 0
while n < 5:
print(n)
n += 1

break, continue, loop-else

  • break — exit the innermost loop.
  • continue — skip to next iteration.
  • else after for/while — runs only if the loop finished without break.
1
2
3
4
5
6
7
8
for n in range(2, 20):
for d in range(2, n):
if n % d == 0:
print(f"{n} = {d} * {n // d}")
break
else:
print(f"{n} is prime")

The else runs only when the inner for completes without finding a divisor → the number is prime. This is a Python-unique idiom worth memorising.

How a loop ends: continue, break and the else block, traced with the prime-number example


Chapter 7 — Comments and docstrings

1
2
3
4
5
6
7
8
9
10
11
12
13
# single-line comment

"""
This is a triple-quoted string. When it's the first thing in a function,
class, or module, it becomes the *docstring* — accessible via help() or __doc__.
"""


def add(a, b):
"""Return the sum of a and b."""
return a + b

help(add) # shows the docstring

Practice Exercises

Exercise 1 — FizzBuzz

The legendary interview problem. Print numbers 1–100. For multiples of 3, print "Fizz". For multiples of 5, print "Buzz". For multiples of both, print "FizzBuzz".

Solution
1
2
3
4
5
6
7
8
9
10
for i in range(1, 101):
if i % 15 == 0:
print("FizzBuzz")
elif i % 3 == 0:
print("Fizz")
elif i % 5 == 0:
print("Buzz")
else:
print(i)

Exercise 2 — Sum of digits

Given a positive integer (input from user), print the sum of its digits. Example: 123 → 6.

Solution
1
2
3
4
5
6
7
n = int(input("Number: "))
total = 0
while n > 0:
total += n % 10
n //= 10
print(total)

Exercise 3 — Number guessing game

The computer picks a random number 1–100. The user guesses; you print "too high", "too low", or "correct!". Limit to 7 guesses.

Solution
1
2
3
4
5
6
7
8
9
10
11
import random
target = random.randint(1, 100)
for attempt in range(1, 8):
g = int(input(f"Guess {attempt}/7: "))
if g == target:
print(f"Correct in {attempt} guesses!")
break
print("too low" if g < target else "too high")
else:
print(f"Out of guesses. It was {target}.")

Exercise 4 — Average of inputs

Keep asking for numbers until the user enters an empty line. Print the count and average.

Solution
1
2
3
4
5
6
7
8
9
10
11
nums = []
while True:
s = input("Number (empty to stop): ")
if s == "":
break
nums.append(float(s))
if nums:
print(f"Count: {len(nums)}, average: {sum(nums) / len(nums):.2f}")
else:
print("No numbers entered.")

Cheat-sheet

What How
Variable assign x = 5
Type check type(x) or isinstance(x, int)
f-string f"{name} is {age}"
String slice s[1:4], s[::-1] (reverse)
Integer divide //, modulo %, power **
Chained compare 0 < x < 10
Conditional if ... elif ... else:
Ternary a if cond else b
Range range(start, stop, step)
Enumerate for i, v in enumerate(seq):
Loop with else runs if no break
Falsy values False, 0, "", [], {}, None
Indent 4 spaces, no tabs

What's next

Post 02 covers Python's data structures: list, tuple, dict, set, and the powerful comprehension syntax that lets you transform one structure into another in a single line.


References

Note: this post is in progress. Planned additions: walrus operator :=, match pattern destructuring examples.