Skip to main content

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

RuleExample
Lowercase letters, numbers, underscores onlyrecord_count
Cannot start with a number1st_record
No spacesrecord count
Case-sensitiveCitycity
Cannot be a Python keywordfor, 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 age
age == 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

TypeKeywordExampleCan do math?Typical use
Integerint42, -7, 0YesCounts, IDs, row numbers
Floatfloat3.14, -0.5YesPrices, rates, percentages
Stringstr"hello", '42'No (text operations)Names, labels, file paths
BooleanboolTrue, FalseNoFlags, 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.2 in Python returns 0.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

FunctionConverts toExampleResult
int()Integerint("250")250
float()Floatfloat("3.5")3.5
str()Stringstr(4096)"4096"

⚠ Common Mistake — int() truncates, it does not round

print(int(99.9)) # Returns 99, not 100
print(int(4.7)) # Returns 4, not 5
99
4

Use 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

OperatorNameExampleResult
+Addition10 + 313
-Subtraction10 - 37
*Multiplication10 * 330
/Division10 / 33.333...
//Floor division10 // 33
%Modulo10 % 31
**Exponentiation10 ** 31000

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

ListTuple
Syntax[1, 2, 3](1, 2, 3)
Can change?Yes — add, remove, editNo — fixed once created
Use whenData changes over timeData is fixed (coordinates, config, records)
SpeedSlightly slowerSlightly 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 typeint, 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?