Chapter 6 of 24 · Python for Beginners — Complete Free Tutorial
Control Flow and Conditionals
Every program so far in the Python for Beginners series has run from top to bottom. Conditions change that: if lets a program pick a path, and the rules Python uses to decide what counts as true are shorter — and stricter — than JavaScript’. This chapter covers if, elif and else, the truthiness table, chained conditions, the conditional expression, the three boolean operators and how they short-circuit, and the difference between is and ==.
if, elif and else
A conditional is a keyword, a colon and an indented block. Python evaluates the conditions in order and runs the first branch whose test is true; everything after it is skipped. else is the fallback and takes no condition of its own:
score = 78
if score >= 90:
grade = "A"
elif score >= 80:
grade = "B"
elif score >= 70:
grade = "C"
else:
grade = "D"
print("Score:", score, "Grade:", grade)
Expected output:
Score: 78 Grade: C
Order matters: the tests are mutually exclusive only because they descend. Put the score >= 70 branch first and every passing score would sort into “C”. Because only one branch can run, Python also guarantees a single assignment — but nothing forces you to write an else, and a condition with no matching branch simply leaves the variables untouched.
Truthiness: what counts as false
Conditions do not need a bool; Python asks the value itself. Almost everything is truthy, and a small, fixed list of values is falsy. Memorise the list once and you never have to look anything up:
FalseandNone— the explicit boolean and the “no value here” object.- Any numeric zero:
0,0.0,0j— zeros only, never a near-zero. - Empty text and containers:
"",[],{}andset()— note{}on its own is an empty dict. - Everything else is truthy — including
"0",[0]and{0: 0}.
print(bool(0), bool(0.0), bool(""), bool([]), bool({}), bool(set()), bool(None), bool(False))
Expected output:
False False False False False False False False
[0] is truthy because the list is not empty — truthiness asks about structure, not about the values inside. The same rule powers the shortcut name = user_input or "anonymous": or returns its first truthy operand, so an empty string falls through to the default.
Chained comparisons in conditions
Chapter 5 introduced 0 <= score <= 100; in an if it is where it belongs. The chain is sugar for 0 <= score and score <= 100, evaluated with score read once and in order — the second test is only reached if the first passed:
age = 17
if 0 <= age < 18:
print("junior ticket")
if 12 <= age <= 65:
print("standard ticket")
Expected output:
junior ticket
standard ticket
The conditional expression (ternary)
Python has no condition ? a : b, but it has an expression form that fits on one line: value if condition else value. Use it for short assignments, never for statements — a multi-branch decision belongs in an if:
age = 17
status = "adult" if age >= 18 else "minor"
print(status)
Expected output:
minor
and, or, not — and short-circuiting
Boolean operators in Python are not symbol-shaped, and they are lazy. and stops as soon as an operand is falsy; or stops as soon as one is truthy — the right-hand side is never evaluated unless it is needed:
x = 10
print(x > 5 and x < 20)
print(not x)
y = 0
left = y and print("and evaluates this")
print("left =", left)
z = 5
right = z or print("or evaluates this")
print("right =", right)
Expected output:
True
False
left = 0
right = 5
Neither print() inside the expressions ran — the first line of each pair returned before reaching them. Note also what is returned: and and or hand back one of their operands, not a boolean. y and … returned 0 (the falsy left operand), z or … returned 5. That is how x or "default" works, and it is the same idea as JavaScript’s || and ?? — except Python insists on real booleans nowhere and evaluates truthiness with the table above. not is the only operator that always produces a bool.
Short-circuiting is also a safety tool: if user is not None and user["name"] never indexes None, because the second half cannot run.
Identity: is versus ==
== asks whether two values are equal; is asks whether two names point at the same object. For immutable values the difference rarely shows, but it decides the truth about containers:
a = [1, 2, 3]
b = [1, 2, 3]
print(a == b)
print(a is b)
Expected output:
True
False
The two lists hold equal values but are separate objects, so is correctly says no. Two rules cover everyday use: compare values with ==, and test for a missing value with is None (or is not None) — never with == None, and never with x is True, which tests identity against one particular bool object instead of asking whether the value is truthy.
A worked decision program
Conditions, chaining, and and fallbacks in one short program. Predict the output before you run it:
age = 15
is_student = True
if age < 12:
ticket = 8
elif age < 18:
ticket = 10
else:
ticket = 14
if is_student and ticket > 5:
ticket = ticket - 4
if ticket <= 10:
message = "Budget-friendly"
elif ticket <= 15:
message = "Standard price"
else:
message = "Premium event"
print("Ticket:", ticket)
print("Message:", message)
Expected output:
Ticket: 6
Message: Budget-friendly
Trace it: age = 15 meets the second branch and sets ticket = 10; the student discount applies because is_student is true and the ticket is above 5, giving 6; and 6 lands in the first range of the second decision. Three if statements, one value flowing through them — this is the shape of most business logic you will ever write.
Common mistakes
- Using
=instead of==— an assignment is not a condition; Python flagsif score = 78:as aSyntaxErrorbefore anything runs. - Assuming
eliforder does not matter — the first true branch wins, so overlapping ranges must be written from the most specific to the most general. - Testing truthiness when you meant
None—if not value:also rejects0and""; useif value is None:when absence is the only thing you mean. - Porting JavaScript’s truthy rules —
"false"and"0"are truthy here too (they are non-empty strings), while0is falsy in both languages. - Writing
if x == True:— it fails for1and works forTrueby accident; writeif x:orif x is True:deliberately.
Practice checklist
- Extend the grade program to emit
"A+"for 97 and above and"incomplete"for scores below 40. - Write out the eight falsy values from memory, run
bool()on each, and add three truthy values that beginners guess wrongly. - Rewrite
status = "adult" if age >= 18 else "minor"as anifblock, then convert a three-branchifback into a conditional expression. - Prove short-circuiting: add a second condition that would raise an error if evaluated, and show that
andnever reaches it. - Build two lists with equal contents and print
==andisfor them; then replace every== Nonein your notes withis None.
What's next?
The program can now decide between paths, but only once per run. Next you make it repeat — Loops and Iteration.
Frequently Asked Questions
Python is a general-purpose language first released in 1991, designed around one idea: code is read far more often than it is written. English keywords and indentation instead of braces make it readable, the standard library covers files, JSON, dates and testing, and pip adds thousands more packages. The same language handles scripts, web APIs, data work and machine learning.
None at all. Python is widely considered the friendliest first language: no declaration keywords, no braces, no build step, and error messages that name the problem. This series begins at your first print() call. If you already read JavaScript or TypeScript you will adjust quickly, but no previous language is assumed anywhere in these 24 chapters.
Python 3 only, any release from 3.12 onwards. Python 2 reached end of life in 2021 and its print "hi" statements and xrange() no longer run. One historical quirk remains: installers ship the interpreter as python3 on macOS and Linux, while Windows usually offers python or the py launcher, and every command in this series works with that one-word swap.
More than you might expect. Everyday automation such as renaming files, cleaning spreadsheets or scraping pages; web backends with Django, Flask or FastAPI; data analysis and machine learning with pandas, NumPy and PyTorch; DevOps tooling, desktop apps and games. Python is also the classic glue language, calling C, Rust or Fortran libraries from short readable scripts.
Pure Python can run 10 to 100 times slower than C, yet that rarely blocks you: heavy numeric work lives in C extensions such as NumPy, which Python coordinates. Dynamic typing does push errors to runtime, surfacing as a TypeError on the line that finally uses the bad value. Type hints checked by mypy move those mistakes back into your editor.
Only the interpreter. Install CPython from python.org, version 3.12 or newer, confirm it with python3 --version, and open a plain text editor; VS Code with the Python extension is the recommendation here. The early chapters use no third-party packages, so there is nothing else to set up until virtual environments and pip arrive.
A dict is a real runtime mapping: keys may be any hashable value rather than only strings, insertion order has been guaranteed since Python 3.7, and a missing key raises KeyError unless you ask with get(). JavaScript objects coerce every key to a string and carry a prototype chain. A TypeScript interface is erased at compile time and describes shape only; TypedDict is Python's checked equivalent.
Reach for a list when items will be added, removed or reordered: it is ordered, mutable and rich with methods. Pick a tuple for fixed records and function returns, because it is immutable and hashable, so it can be a dictionary key. Choose a set for unique values and fast membership checks; it has no order and de-duplicates on creation.
Yes, gradually. Annotate public function signatures first; the interpreter ignores hints at runtime, so a checker such as mypy is what gives them teeth. Add tests the same way: pytest collects any test_*.py file and plain assert statements, and a suite that finishes in a tenth of a second is one you will run after every change. Both habits cost little now and much more later.
JavaScript and TypeScript keep the browser, so anything rendered to the user stays theirs. Python takes the server: Django for full-featured applications, Flask for small ones, FastAPI for typed async APIs where your annotations become automatic documentation. Your TypeScript habits transfer directly, and asyncio mirrors the event loop you already know, just with different keywords.