Chapter 13: Python Foundations
Python is one of the most readable programming languages ever written. That is not an accident. Its creator, Guido van Rossum, designed it in the early 1990s with one strong opinion: code is read far more often than it is written, so readability should come first. The result is a language that looks almost like plain English, where the structure of a program is visible at a glance.
This chapter starts from zero. Pay attention to the small things — naming conventions, type rules, how operators behave. These basics appear in every program you will write from here on.
13.1 Your First Python Program
Open a terminal and type python3 to launch the interactive shell:
Python 3.12.0 (main, Oct 2 2023)
>>>
The >>> prompt means Python is waiting. Type the following and press Enter:
print("Hello, World!")
Hello, World!
print() displays whatever you put inside its parentheses. The quotes tell Python that Hello, World! is text, not a command.
For anything longer than a few lines, write your code in a .py file and run it with:
python3 my_script.py
Try It 13.1 — Print your name, then your city. Two separate
print()statements, two separate lines of output.
13.2 Variables
A variable is a name attached to a value stored in memory. When you write:
city = "Karachi"
Python stores "Karachi" in memory and labels it city. Wherever you write city in your code, Python substitutes "Karachi".
city = "Karachi"
temperature = 38
print(city)
print(temperature)
Karachi
38
A variable's value can change. Write a new assignment and the old value is replaced:
score = 10
print(score)
score = 25
print(score)
10
25
How Variable Assignment Works
┌─────────────────┐
city ───────▶│ "Karachi" │ (stored in memory)
└─────────────────┘
┌─────────────────┐
temperature ───▶│ 38 │ (stored in memory)
└─────────────────┘
The variable name on the left is the label. The value on the right is what gets stored. The = sign is the assignment operator — it points the label at the value.
Naming Rules
| Rule | Example |
|---|---|
| Lowercase letters, numbers, underscores only | record_count ✓ |
| Cannot start with a number | 1st_record ✗ |
| No spaces | record count ✗ |
| Case-sensitive | City ≠ city |
| Cannot be a Python keyword | for, if, while ✗ |
The Python convention is snake_case — all lowercase, underscores between words. So open_tickets, not OpenTickets or openTickets.
Names matter more than they seem:
# Hard to understand later
x = 500
y = 0.17
z = x * y
# Clear immediately
revenue = 500
tax_rate = 0.17
tax_amount = revenue * tax_rate
Both produce identical results. Only one is readable in six months.
Try It 13.2 — Create three variables: a person's name, their age, and their city. Print all three.
⚠ Common Mistake —
=is not==age = 25 # assigns 25 to ageage == 25 # checks whether age equals 25 (True/False)A single
=assigns. A double==compares. Python will either raise an error or silently do the wrong thing when you mix them up.
13.3 Data Types
Every value in Python has a type. The type controls what you can do with it — you can divide two numbers, but not two names.
The Four Core Types
| Type | Keyword | Example | Can do math? | Typical use |
|---|---|---|---|---|
| Integer | int | 42, -7, 0 | Yes | Counts, IDs, row numbers |
| Float | float | 3.14, -0.5 | Yes | Prices, rates, percentages |
| String | str | "hello", '42' | No (text operations) | Names, labels, file paths |
| Boolean | bool | True, False | No | Flags, conditions, comparisons |
13.3.1 Integers — int
Whole numbers, positive or negative.
rows_loaded = 9500
rows_expected = 10000
rows_failed = rows_expected - rows_loaded
print(rows_failed)
500
13.3.2 Floats — float
Numbers with a decimal point.
budget = 50000.00
spent = 32750.50
remaining = budget - spent
print(remaining)
17249.5
Note:
0.1 + 0.2in Python returns0.30000000000000004. Not a bug — it is how all computers store decimals in binary. For most work it is harmless.
13.3.3 Strings — str
Any sequence of characters. Single quotes, double quotes, or triple quotes for multi-line text.
name = "Sarah"
status = 'active'
message = """
Account: Sarah
Status: Active
Plan: Pro
"""
print(name)
print(status)
print(message)
Sarah
active
Account: Sarah
Status: Active
Plan: Pro
Joining two strings uses + — this is called concatenation:
first = "Data"
second = "Engineer"
role = first + " " + second
print(role)
Data Engineer
13.3.4 Booleans — bool
Holds exactly one of two values: True or False. Always comes from a comparison.
files_processed = 47
target = 50
target_met = files_processed >= target
print(target_met)
False
Use type() to check any value's type:
print(type(100))
print(type(3.14))
print(type("hello"))
print(type(True))
<class 'int'>
<class 'float'>
<class 'str'>
<class 'bool'>
Try It 13.3 — Create one variable of each type. Print each with its
type().
13.4 Type Conversion
Data rarely arrives in the right type. A CSV file gives you numbers as strings. User input is always a string, even if someone typed 42. Conversion fixes this.
count = "4500" # came in as text
print(type(count))
count = int(count) # converted to integer
print(type(count))
print(count + 500)
<class 'str'>
<class 'int'>
5000
Conversion Functions at a Glance
| Function | Converts to | Example | Result |
|---|---|---|---|
int() | Integer | int("250") | 250 |
float() | Float | float("3.5") | 3.5 |
str() | String | str(4096) | "4096" |
⚠ Common Mistake —
int()truncates, it does not roundprint(int(99.9)) # Returns 99, not 100print(int(4.7)) # Returns 4, not 5994Use
round()when you need rounding.int()simply drops everything after the decimal.
Conversion fails when the value makes no sense as the target type:
int("hello")
ValueError: invalid literal for int() with base 10: 'hello'
13.5 Operators
13.5.1 Arithmetic Operators
a = 17
b = 5
print(a + b) # 22
print(a - b) # 12
print(a * b) # 85
print(a / b) # 3.4 — always a float
print(a // b) # 3 — floor division, drops decimal
print(a % b) # 2 — modulo, the remainder
print(a ** 2) # 289 — exponentiation
22
12
85
3.4
3
2
289
Operator Reference
| Operator | Name | Example | Result |
|---|---|---|---|
+ | Addition | 10 + 3 | 13 |
- | Subtraction | 10 - 3 | 7 |
* | Multiplication | 10 * 3 | 30 |
/ | Division | 10 / 3 | 3.333... |
// | Floor division | 10 // 3 | 3 |
% | Modulo | 10 % 3 | 1 |
** | Exponentiation | 10 ** 3 | 1000 |
The modulo operator % deserves attention. 17 % 5 asks: after dividing 17 by 5, what is left over? The answer is 2. You will use this to check whether a number is even (n % 2 == 0), trigger logic every nth item, or split records into batches.
13.5.2 Comparison Operators
Comparisons always return a boolean:
score = 87
print(score == 100) # False — equal
print(score != 100) # True — not equal
print(score > 80) # True — greater than
print(score >= 87) # True — greater than or equal
print(score < 50) # False — less than
False
True
True
True
False
Try It 13.4 — A batch job loaded 9,847 out of 10,000 expected records. Calculate the success rate, then check whether it is above 98.5%.
13.6 Comments
Python ignores any line that starts with #. Comments are for humans — whoever reads the code next, including you six months from now.
# Count of files successfully processed today
files_done = 142
total_files = 150
success_rate = (files_done / total_files) * 100 # expressed as percentage
print(success_rate)
94.66666666666667
The general rule: comment on why, not what. The code already says what it does. Comments explain the reason behind a decision.
# Subtract 1 because the downstream system uses zero-based partition indexing
partition_id = (batch_number - 1)
13.7 Lists
A list holds multiple values in a single variable, in order. You create one with square brackets:
cities = ["Karachi", "Lahore", "Islamabad", "Peshawar"]
scores = [88, 92, 74, 95, 61]
Accessing Items
Every item in a list has an index — its position number, starting from 0.
Index: 0 1 2 3
┌──────────┬──────────┬────────────┬──────────┐
│ "Karachi"│ "Lahore" │"Islamabad" │"Peshawar"│
└──────────┴──────────┴────────────┴──────────┘
cities = ["Karachi", "Lahore", "Islamabad", "Peshawar"]
print(cities[0]) # First item
print(cities[2]) # Third item
print(cities[-1]) # Last item (negative index counts from end)
Karachi
Islamabad
Peshawar
Adding Items — append()
append() adds a new item to the end of the list:
cities = ["Karachi", "Lahore"]
cities.append("Quetta")
print(cities)
['Karachi', 'Lahore', 'Quetta']
Removing Items — pop()
pop() removes and returns the last item. Pass an index to remove a specific item:
cities = ["Karachi", "Lahore", "Islamabad"]
last = cities.pop() # removes and returns "Islamabad"
print(last)
print(cities)
removed = cities.pop(0) # removes and returns "Karachi"
print(removed)
print(cities)
Islamabad
['Karachi', 'Lahore']
Karachi
['Lahore']
List Length
len() returns the number of items in a list:
scores = [88, 92, 74, 95, 61]
print(len(scores))
5
Try It 13.5 — Create a list of five country names. Print the first and last items. Append a new country. Pop the second item and print what was removed. Print the final list.
13.8 Tuples
A tuple looks like a list but uses parentheses instead of square brackets — and it cannot be changed after it is created.
coordinates = (24.8607, 67.0011) # latitude, longitude
rgb = (255, 128, 0) # a colour
List vs Tuple — When to Use Which
| List | Tuple | |
|---|---|---|
| Syntax | [1, 2, 3] | (1, 2, 3) |
| Can change? | Yes — add, remove, edit | No — fixed once created |
| Use when | Data changes over time | Data is fixed (coordinates, config, records) |
| Speed | Slightly slower | Slightly faster |
# A list — can grow and shrink
pipeline_steps = ["extract", "transform", "load"]
pipeline_steps.append("validate")
print(pipeline_steps)
# A tuple — fixed, cannot be modified
db_config = ("localhost", 5432, "mydb")
print(db_config[0]) # access by index, same as list
print(db_config[1])
['extract', 'transform', 'load', 'validate']
localhost
5432
Trying to modify a tuple raises an error:
db_config = ("localhost", 5432, "mydb")
db_config[1] = 3306
TypeError: 'tuple' object does not support item assignment
This is intentional. Use a tuple when the data should never change — coordinates, settings, database credentials, column names. Use a list when the data will grow or be modified.
Try It 13.6 — Create a tuple with three server configuration values (host, port, database name). Print each value using its index. Try changing one value and observe the error.
13.9 Putting It Together
Here is a small program that uses everything from this chapter. Ayan is tracking project data for a client review:
# Client project summary
client = "Danial"
project = "Cloud Infrastructure Upgrade"
budget = 75000.00
tasks = ["planning", "setup", "migration", "testing"]
tasks_done = 2
completion = (tasks_done / len(tasks)) * 100
on_budget = budget <= 80000.00
tasks.append("handover") # new phase added
print("Client: " + client)
print("Project: " + project)
print("Progress: " + str(round(completion, 1)) + "%")
print("On budget: " + str(on_budget))
print("Phases: " + str(tasks))
print("Total phases: " + str(len(tasks)))
Client: Danial
Project: Cloud Infrastructure Upgrade
Progress: 50.0%
On budget: True
Phases: ['planning', 'setup', 'migration', 'testing', 'handover']
Total phases: 5
Every concept from this chapter appears here: variables, strings, a float, a boolean, arithmetic, a list, append(), len(), and type conversion for the print statements.
Summary
Python stores values in variables, and every value has a type — int, float, str, or bool. The type controls what operations are valid. When data arrives in the wrong type, conversion functions (int(), float(), str()) fix it — but int() truncates rather than rounds. Arithmetic operators handle math; comparison operators return booleans. Comments explain why, not what. A list holds ordered values that can grow and change — use append() to add and pop() to remove. A tuple holds ordered values that are fixed — use one when the data should never change.
Exercises
13.1 — Create four variables: a string, an integer, a float, and a boolean. Print each with its type(). Then convert the integer to a float and the float to a string and print both results.
13.2 — You have a storage budget of 500 GB. A pipeline writes 37 GB per day. Calculate how many full days until the storage runs out, and how many GB remain on the last day. Use only // and %.
13.3 — The following code has a bug. Find it and explain exactly what Python will do when it runs:
limit = 1000
if limit = 1000:
print("Limit reached")
13.4 — Create a list of five scores. Print the highest (use max()), lowest (use min()), and the total (use sum()). Then append one more score and print the new average.
13.5 — What is the difference between [10, 20, 30] and (10, 20, 30)? Write a short program that demonstrates one operation that works on a list but fails on a tuple. Explain why the distinction matters.
13.6 — A rate comes in as the string "98.6". Write the steps to convert it to an integer 98 without losing the intermediate float. What would happen if you called int("98.6") directly, and why?