Beginner

Python 3 Fundamentals

Python is a great programming language for beginners and experts alike because it's easy to learn and use, and it has libraries that allow you to build just about anything: from data scie...

Table of Contents

  1. Module 1 — Course presentation
  2. Module 2 — Run Python and explore data types
  1. Conditionals and Imports
  1. Lists and Loops
  1. Module 5 — Dictionaries, JSON and Pip
  1. Functions
  1. Classes and Objects
  1. Working with Files

1. Course overview

Welcome to this Python 3 Fundamentals training. Python is a great programming language for beginners and experts alike because it’s easy to learn and use, and it has libraries that allow you to build just about anything: from data science to machine learning to web development.

In this course, we will learn the fundamentals of Python while building practical programs, including:

  • A loan calculator
  • A game Rock, Paper, Scissors (Rock, Paper, Scissors)
  • An acronym translator (acronym translator)
  • A weather reader

Major topics covered include:

  • Write a Python program
  • Inputs and outputs
  • Data types
  • Web requests
  • Install and use Python packages

By the end of this course, you will master the fundamentals of Python and have real-world experience building practical Python programs. This course starts from scratch, no prerequisites are necessary.


2. Running Python and exploring data types

2.1 Introduction to data types

In this module, we will dive into data types and input/output. Before we get started, here’s why Python is a great choice:

  1. Versatility: You can use Python for just about anything — data science, machine learning, web development, and more.
  2. Strong Community: There is a Python library for just about anything.
  3. Ease of learning: Python is concise, close to English or another written language.

Module objective

At the end of this module, we will create a simple program that tells you your age in decades and years. The program asks your age, and then displays how many decades and years that represents.

Variables and numeric types

There are two ways to write Python code:

  1. The Python interactive shell (Python interactive shell): we see three small chevrons >>> and we write Python code line by line.
  2. A Python file (Python script): we write longer programs.

In Python, you can assign values ​​to variables:

# Assigner des valeurs
x = 5          # int (entier)
y = 2.5        # float (décimal)
z = x + y      # z = 7.5

Basic numeric types in Python:

  • int: integer, e.g. 5, 100, -3
  • float: decimal number, e.g. 2.5, 3.14, -0.7

Available arithmetic operators:

OperatorDescriptionExample
+Addition5 + 3 = 8
-Subtraction5 - 3 = 2
*Multiplication5 * 3 = 15
/Dividing (float)5 / 2 = 2.5
//Integer division5 // 2 = 2
%Modulo (rest)5% 2 = 1
**Power (exponent)2 ** 3 = 8

integer division (//) is particularly useful for calculating decades: 37 // 10 = 3 decades. The modulo (%) gives the remainder: 37 % 10 = 7 years remaining.


2.2 Demo: Install Python and VS Code

Before installing Python, check if it is already installed:

  • On Windows: open a command prompt (Command Prompt) and type python --version. If Python is installed, we will see a version number like Python 3.11. Otherwise, a “Python was not found” message is displayed.
  • On Mac: open the terminal and type python --version. Python 2 is often already installed by default. For Python 3, type python3 --version. If Python 3 is not installed, you will see “command not found”.

Installing Python

  1. Open a web browser and go to python.org/downloads.
  2. Click on the large Download button which automatically detects your operating system.
  3. Launch the installer and follow the default options.
  4. Important on Windows: check the option “Add python.exe to PATH” so as not to have to manually modify the environment variables.
  5. After installation, reopen the terminal or command prompt and type python --version to check.

Installing Visual Studio Code (VS Code)

Visual Studio Code is the recommended editor for this course. To install it:

  1. Go to code.visualstudio.com.
  2. Download and install VS Code for your operating system.
  3. After installation, create a new folder for your Python course, for example PythonCourse.
  4. In VS Code, install the Python extension (search for “Python” in the Extensions tab).
  5. Create a new .py file and click the Run button to execute.

2.3 Demo: Create a tax calculator

Now that Python and VS Code are installed, follow me to create a sales tax calculation program.

With the interactive shell

>>> amount = 10
>>> tax = 0.06
>>> total = amount + amount * tax
>>> total
10.6

The result is 10.6, or $10.60. The interactive shell is useful for testing a few lines, but if you want to change the values, you have to retype everything.

>>> amount = 100
>>> total = amount + amount * tax
>>> total
106.0

Create a Python script — tax.py

The way to save and reuse a program is to create a Python script. We open VS Code, create a tax.py file, and copy our code into it. Unlike the interactive shell, to display a value in a script, you must use the print function:

amount = 200
tax = 0.07
total = amount + amount * tax
print(total)

File: 02/demos/demos/tax.py


2.4 Strings and input/output (Input/Output)

The print function

print is a Python built-in function. We use it by typing print then the value to display in parentheses (the argument). We can think of it as a black box machine: we don’t know exactly how it works, but we know that when we call it with an argument, it displays the value on the screen.

print(10.6)   # Affiche : 10.6

Type conversions (type conversion)

To convert a float to int (we cut the decimal part):

print(int(10.6))   # Affiche : 10

To force an int to be a float:

print(float(10))   # Affiche : 10.0

Strings

Anything enclosed in single or double quotes is called text and is called a string. The name variable below is of type string:

name = "Sarah"
print(name)   # Affiche : Sarah (sans les guillemets)

Single or double quotes can be used. Double quotes are useful when the string contains an apostrophe:

store_name = "Sarah's Store"   # Correct — guillemets doubles
# store_name = 'Sarah's Store'  # ERREUR — l'apostrophe ferme le string prématurément

String concatenation

To join (concatenate) two strings, we use the + operator:

first = "Sarah"
last = "Holderness"
full_name = first + " " + last
print(full_name)   # Affiche : Sarah Holderness

Converting a number to a string

To concatenate a number with a string, you must first convert it to a string with str():

age = 37
print("I am " + str(age) + " years old.")

f-strings (formatted strings literals)

Another elegant way to embed variables in a string is to use f-strings:

age = 37
print(f"I am {age} years old.")

The input function

The input function displays a message (prompt) to the user and returns what the user typed, always as a string:

name = input("What is your name? ")
print("Hello, " + name)

To go to the line in the prompt, we use \n (newline) in the string:

name = input("What is your name?\n")

This causes the question to be displayed on one line and the user types their answer on the next line.

Primitive data types — summary

TypeDescriptionExample
intInteger5, 100
floatDecimal number3.14, 2.5
strText (string)"hello", 'a'
boolBoolean (true/false)True, False

Now that we know how to get user data, save it, do calculations, convert numbers to text and display the results, we have everything we need to create the age calculator.


2.5 Demo: Age calculator in decades

Do you know how many decades you are? Let’s create a program to find out.

Purpose: Ask the user for age and display how many decades and years that represents.

Step by step development

Step 1: query age with input, save in age, then calculate decades.

If we try age / 10, we get an error TypeError: unsupported operand type(s) for /: 'str' and 'int' — because input always returns a string.

Step 2: convert the input to int with the int() function.

Step 3: use integer division // to get an integer number of decades, and modulo % for the remaining years.

Typical error: if we try to concatenate a float with a string, we get TypeError: can only concatenate str (not "float") to str. You must convert with str().

File: 02/demos/demos/decades.py

age = int(input("How old are you?\n"))

decades = age // 10
years = age % 10

print("You are " + str(decades) + 
      " decades and " + str(years) + " years old.")

Execution example:

How old are you?
37
You are 3 decades and 7 years old.

3. Conditionals and Imports

3.1 Conditionals (if/elif/else)

Computer programs must be able to make decisions. How to make these decisions? A conditional statement, or if statement, allows us to make decisions in Python.

Real life example: hiking app

Let’s imagine a hiking application that needs to display weather warnings:

  • If it’s sunny and 90 degrees or higher, it’s too hot.
  • If it rains, we stay inside.
  • Otherwise, we go out and enjoy the outdoors.

Comparators

There are six comparators in Python:

ComparatorDescriptionExample
<Less than3 < 5True
<=Less than or equal to5 <= 5True
==Equal to5 == 5True
>Greater than7 > 5True
>=Greater than or equal to5 >= 5True
!=Different from3 != 5True

Warning: assignment uses = (one equal sign) and comparison uses == (two equal signs).

temp = 95
temp == 95   # True
temp < 90    # False

Structure of an if statement

An if statement allows you to decide what to do. It’s like saying, “If this comparison is true, then do this block of code.”

temp = 95
if temp > 80:
    print("It's hot outside.")
    print("Drink water!")

Since temp > 80 is True, both print instructions are executed.

Important: indentation (4 spaces or 1 tab) defines the block of code inside the if. All indented lines are part of the if block.

if / elif / else

To manage multiple conditions:

temp = 95
forecast = "sunny"

if temp >= 90 and forecast == "sunny":
    print("It's too hot. Stay inside.")
elif forecast == "raining":
    print("It's raining. Stay inside.")
else:
    print("Let's go enjoy the outdoors!")
  • The keyword elif (contraction of “else if”) tests a new condition if the previous one is false.
  • The else block executes if no previous condition is true.
  • You can have as many elif blocks as you want, but only one else at the end.

Logical operators

OperatorDescription
andTrue if both conditions are true
orTrue if at least one condition is true
notInvert Boolean value
temp = 95
forecast = "sunny"

# and : les deux doivent être vraies
if temp >= 90 and forecast == "sunny":
    print("Too hot!")

# or : au moins une doit être vraie
if temp >= 90 or forecast == "raining":
    print("Stay inside.")

3.2 Demo: Rock, Paper, Scissors Game

In this demo, we will create the game Rock, Paper, Scissors.

Objective: the computer plays against the user.

File: 03/demos/demos/rock_paper_scissors.py

computer_choice = 'scissors'

user_choice = input("Do you want - rock, paper, or scissors?\n")

if computer_choice == user_choice:
    print('TIE')
elif user_choice == 'rock' and computer_choice == 'scissors':
    print('WIN')
elif user_choice == 'paper' and computer_choice == 'rock':
    print('WIN')
elif user_choice == 'scissors' and computer_choice == 'paper':
    print('WIN')
else:
    print('You lose :( Computer wins :D')

Code analysis

  1. We initialize computer_choice to 'scissors' (for the moment, this is fixed).
  2. The user is asked for their choice with input.
  3. Equality: if the two choices are identical → TIE.
  4. The user wins in 3 cases:
  • rock beats scissors
  • paper beats rock
  • scissors beats paper
  1. Otherwiseelse: the computer wins.

When we test with user_choice = 'paper' and computer_choice = 'scissors', nothing is displayed — which is correct: the if is false, there is nothing after it, and the else would handle this case if we had tested it (the user loses).


3.3 Import Python modules

To make the game more fun, the computer must choose randomly. How ? Using the random module from the Python Standard Library.

The Python Standard Library

When we install Python, we obtain:

  1. The Python interpreter (Python interpreter) with all its built-in types and functions.
  2. The Python Standard Library: modules with additional features for mathematics, dates and times, random number generation, etc.

Documentation is available at docs.python.org/3/library.

The random module

In the Standard Library, the random module provides functions for generating random numbers. The random.randint(a, b) function returns a random integer between a and b (inclusive).

Import and use a module

We use the import keyword at the top of the file:

import random

roll = random.randint(1, 6)
print("You rolled:", roll)
  • import random makes the functions of the random module available.
  • Functions are accessed with dot notation: random.randint.
  • No need to install this module, it comes with Python.

Simulate a 6-sided die roll

import random

roll = random.randint(1, 6)
print("You rolled:", roll)

Each time it runs, roll will have a different value between 1 and 6.


3.4 Demo: Randomize the game Rock, Paper, Scissors

To create a randomized Rock, Paper, Scissors game, we use the random.choice function which takes a sequence (a list) as an argument and returns a random element from this list.

File: 03/demos/demos/rock_paper_scissors_random.py

import random

computer_choice = random.choice(['rock', 'paper', 'scissors'])
user_choice = input('Do you want rock, paper, or scissors?')

print('Computer choice:', computer_choice)

if computer_choice == user_choice:
    print('TIE')
elif user_choice == 'rock' and computer_choice == 'scissors':
    print('WIN')
elif user_choice == 'paper' and computer_choice == 'rock':
    print('WIN')
elif user_choice == 'scissors' and computer_choice == 'paper':
    print('WIN')
else:
    print('You lose, computer wins :)')

Key Points

  • ['rock', 'paper', 'scissors'] is a list (we will see them in detail in module 4).
  • random.choice(list) returns a random element from the list.
  • We added a print so that the user sees the choice of computer.

Execution example:

Do you want rock, paper, or scissors? rock
Computer choice: paper
You lose, computer wins :)

4. Lists and Loops

4.1 Lists and for loops

A list is a Python container that can store anything. We can have:

  • An empty list
  • A list of strings
  • A list of numbers
  • A list of mixed elements (numbers and strings)
  • A list of lists

Example: storing acronyms

acronyms = ['LOL', 'IDK', 'TBH', 'BFN']

The index (index)

In a list, the index corresponds to the position of an element. In Python (as in most languages), indexing starts at 0:

acronyms = ['LOL', 'IDK', 'TBH', 'BFN']
print(acronyms[0])   # LOL  (premier élément)
print(acronyms[3])   # BFN  (quatrième élément)

In general, to obtain the nth element, we use the index [n-1].

Create and modify a list

# Créer une liste vide et ajouter des éléments avec append
acronyms = []
acronyms.append('LOL')
acronyms.append('IDK')
print(acronyms)   # ['LOL', 'IDK']

# Créer une liste avec des éléments déjà présents
acronyms = ['LOL', 'IDK', 'TBH']
acronyms.append('BFN')   # Ajouter à la fin
print(acronyms)   # ['LOL', 'IDK', 'TBH', 'BFN']

Functions vs methods: We used functions like print() and input(). Methods are called on objects, with the dot notation: liste.append(value).

Delete an item

acronyms.remove('BFN')   # Supprime la valeur BFN
print(acronyms)

If we do not know the value but the index, we use pop(index):

acronyms.pop(0)   # Supprime le premier élément (index 0)

The for loop

A for loop allows you to iterate over all the elements of a list:

acronyms = ['LOL', 'IDK', 'TBH']
for acronym in acronyms:
    print(acronym)

Output:

LOL
IDK
TBH

The loop variable (acronym) takes the value of each element in each iteration. It can be named anything (often x for short, or a descriptive name).

Length of a list with len()

print(len(acronyms))   # 3

4.2 Demo: Calculate the sum of expenses

In this demo, we will calculate the sum of all expenses in a list.

Objective: collect the 7 lunch tickets of the week.

File: 04/demos/demos/expenses.py

expenses = [10.50, 8, 5, 15, 20, 5, 3]

total = sum(expenses)

print('You spent $', total, sep='')

Step by step development

Version with manual loop:

expenses = [10.50, 8, 5, 15, 20, 5, 3]

sum = 0
for x in expenses:
    sum = sum + x

print('You spent $', sum, sep='')

Output: You spent $66.5

  • We initialize sum = 0.
  • At each iteration, we add x (the current expense) to sum.
  • Outside the loop, we display the total.

Separator in print

By default, print adds a space between comma-separated values. To remove this space, we use the sep='' parameter:

print('You spent $', total, sep='')   # Affiche : You spent $66.5

Use the sum() built-in function

Python has a built-in sum() function that can directly sum all elements of a list:

total = sum(expenses)

4.3 Loops with range()

Let’s return to the spending program. If we want the user to enter their expenses themselves rather than using a hard-coded list, we would need to loop a certain number of times.

The range() function

The range() function returns a sequence of numbers that can be traversed with a for loop. For example :

for i in range(7):
    print(i)

Output: 0 1 2 3 4 5 6

range(7) generates a sequence of 7 integers from 0 to 6.

Custom range()

We can give a start, a stop and a step:

# range(start, stop, step)
range(7)         # 0, 1, 2, 3, 4, 5, 6  (équivalent à range(0, 7, 1))
range(2, 14, 2)  # 2, 4, 6, 8, 10, 12  (nombres pairs)

Use range() to enter expenses

expenses = []
for i in range(7):
    expense = float(input("Enter expense: "))
    expenses.append(expense)

total = sum(expenses)
print('You spent $', total, sep='')

Output:

Enter expense: 10.50
Enter expense: 8
...
You spent $72

Dynamic expense count

num_expenses = int(input("How many expenses do you have? "))
expenses = []
for i in range(num_expenses):
    expense = float(input("Enter expense: "))
    expenses.append(expense)

total = sum(expenses)
print('You spent $', total, sep='')

4.4 Demo: Loan Repayment Calculator

In this demo, we will create a loan calculator which calculates the remaining balance after a certain number of monthly payments.

File: 04/demos/demos/loan.py

# Get the loan details
money_owed = float(input("How much money do you owe, in dollars?\n")) # $50,000
apr = float(input("What is the annual percentage rate of the loan?\n")) # 3%
payment = float(input("How much will you pay off each month in dollars?\n")) # $1,000
months = int(input("How many months do you want to see the results for?\n")) # 54

# Divide apr by 100 to make a percent, and 12 to make monthly
monthly_rate = apr / 100 / 12

# Repeat payments exactly months number of times
for i in range(months):

    # Add in interest
    interest_paid = money_owed * monthly_rate
    money_owed = money_owed + interest_paid

    if (money_owed - payment < 0):
        print("The last payment is", money_owed)
        print("You paid off loan in", i + 1, "months")
        break

    # Make payment
    money_owed = money_owed - payment

    # Print results after this month
    print("Paid", payment, "of which", interest_paid, "was interest", end=" ")
    print("Now I owe", money_owed)

Key points of the code

  1. Comments (#): the symbol # (pound or pound) indicates a comment. The Python interpreter ignores comments — they are only used by humans to explain the code.

  2. Conversion from annual rate to monthly rate:

    monthly_rate = apr / 100 / 12
    

Divide by 100 to get a decimal percentage, then by 12 to get the monthly rate.

  1. Calculation of monthly interest:

    interest_paid = money_owed * monthly_rate
    money_owed = money_owed + interest_paid
    
  2. Checking if the loan is repaid:

    if money_owed - payment < 0:
        print("The last payment is", money_owed)
        break
    

The break keyword exits the loop immediately.

  1. end parameter in print: By default, print adds a line break at the end. end=" " replaces this line break with a space, allowing the next print statement to continue on the same line.

Execution example ($50,000, 3%, $1,000/month, 54 months):

Paid 1000.0 of which 125.0 was interest Now I owe 49125.0
Paid 1000.0 of which 122.8125 was interest Now I owe 48247.8125
...
The last payment is 958.4...
You paid off loan in 54 months

5. Dictionaries, JSON and Pip

5.1 Dictionaries

In this module, we will explore dictionaries, reading JSON data, and installing packages with pip.

Problem with two parallel lists

Let’s imagine that we want to store internet acronyms and their translations. We could use two lists:

acronyms = ['LOL', 'IDK', 'TBH']
translations = ['laugh out loud', "I don't know", 'to be honest']

But this poses problems: if you add an element to one list, you have to add it to the other too. If we delete one, we must delete it from both. This can lead to errors.

Solution: the dictionary

A dictionary maps keys to values. Here the keys would be the acronyms and the values ​​their translations.

acronyms = {
    'LOL': 'laugh out loud',
    'IDK': "I don't know",
    'TBH': 'to be honest'
}

In memory: the key 'LOL' is assigned to the value 'laugh out loud', etc. Each element in a dictionary is called a key-value pair.

Access a value

To search for an element, pass the key between square brackets (instead of an index as for a list):

print(acronyms['LOL'])   # Affiche : laugh out loud

Create and modify a dictionary

# Créer un dictionnaire vide
acronyms = {}

# Ajouter des éléments
acronyms['LOL'] = 'laugh out loud'
acronyms['IDK'] = "I don't know"
acronyms['TBH'] = 'to be honest'
print(acronyms)
# {'LOL': 'laugh out loud', 'IDK': "I don't know", 'TBH': 'to be honest'}

# Mettre à jour une valeur (même syntaxe que l'ajout)
acronyms['TBH'] = 'honestly'
print(acronyms['TBH'])   # Affiche : honestly

# Supprimer une paire clé-valeur
del acronyms['LOL']
print(acronyms)   # LOL a été supprimé

The get() method

If we try to access a key that does not exist with square brackets, we get a KeyError which crashes the program. To avoid this, we use the get() method:

result = acronyms.get('LOL')
print(result)   # Affiche : None (pas d'erreur si la clé n'existe pas)

get() returns None if the key is not found, instead of raising an error.

Dictionary types

Dictionaries can contain any type for keys and values:

# Strings → Strings (acronymes)
acronyms = {'LOL': 'laugh out loud', 'IDK': "I don't know"}

# Strings → Numbers (menu avec prix)
menu = {'coffee': 3.50, 'tea': 2.00, 'juice': 4.00}

# N'importe quel type
mixed = {1: 'one', 'key': [1, 2, 3]}

5.2 Demo: Create a movie times dictionary

In this demo, we’ll create a movie showtimes viewing program — like an old movie theater phone system!

File: 05/demos/demos/movie_schedule.py

current_movies = {'The Grinch': '11:00am',
                 'Rudolph': '1:00pm',
                 'Frosty the Snowman': '3:00pm',
                 'Christmas Vacation': '5:00pm'}

print("We're showing the following movies:")
for key in current_movies:
    print(key)
movie = input('What movie would you like the showtime for?\n')

showtime = current_movies.get(movie)
if showtime == None:
    print("Requested movie isn't playing")
else:
    print(movie, 'is playing at', showtime)

Key Points

  1. Iterate through the keys of a dictionary: by default, a for loop on a dictionary iterates over its keys:

    for key in current_movies:
        print(key)   # Affiche les titres des films
    
  2. Using get(): if the user types a title that is not in the dictionary, get() returns None instead of raising an error.

  3. Handling the “film not found” case: we check if showtime == None with an if/else.

Execution example:

We're showing the following movies:
The Grinch
Rudolph
Frosty the Snowman
Christmas Vacation
What movie would you like the showtime for?
Rudolph
Rudolph is playing at 1:00pm

5.3 Combine lists and dictionaries

Now that we know about dictionaries, let’s explore more complex examples combining lists and dictionaries.

List of lists

In Python, we can have containers of containers:

breakfast = ['Eggs', 'Bagel', 'Toast']
lunch = ['Sandwich', 'Salad', 'Soup']
dinner = ['Steak', 'Pasta', 'Fish']

menu = [breakfast, lunch, dinner]

# Accéder à une liste interne
print(menu[0])   # ['Eggs', 'Bagel', 'Toast']

# Accéder à un élément d'une liste interne (double index)
print(menu[0][1])   # Bagel

Index [0] gets the first list (breakfast), then [1] gets the second item in that list (Bagel).

List dictionary

A clearer organization would be to use a dictionary with descriptive keys:

menu = {
    'breakfast': ['Eggs', 'Bagel', 'Toast'],
    'lunch': ['Sandwich', 'Salad', 'Soup'],
    'dinner': ['Steak', 'Pasta', 'Fish']
}

# Accéder à une liste
print(menu['breakfast'])

For loop over a dictionary with keys and values

If we want the keys and the values ​​in a loop, we use the items() method with two loop variables:

for name, items in menu.items():
    print(name, items)

Output:

breakfast ['Eggs', 'Bagel', 'Toast']
lunch ['Sandwich', 'Salad', 'Soup']
dinner ['Steak', 'Pasta', 'Fish']

If we only want the values, we use values():

for items in menu.values():
    print(items)

5.4 Demo: Parse a nested contacts dictionary

In this demo, we will extract only email addresses from a nested contact dictionary to create a mailing list.

File: 05/demos/demos/contacts.py

contacts = {
    "number": 4,
    "students": [
        {"name": "Sarah Holderness", "email": "sarah@example.com"},
        {"name": "Harry Potter", "email": "harry@example.com"},
        {"name": "Hermione Granger", "email": "hermione@example.com"},
        {"name": "Ron Weasley", "email": "ron@example.com"}
    ]
}

print('Student emails:')
for student in contacts['students']:
    print(student['email'])

Structure analysis

The contacts dictionary has:

  • The key "number" with the value 4 (number of students).
  • The "students" key with a list of dictionaries — each dictionary represents a student with their name and email.

This is a nested structure: a dictionary contains a list, which contains dictionaries.

Access nested data

# Accéder à la liste des étudiants
students = contacts['students']

# Accéder au premier étudiant
first_student = contacts['students'][0]
# {'name': 'Sarah Holderness', 'email': 'sarah@example.com'}

# Accéder à l'email du premier étudiant
email = contacts['students'][0]['email']
# 'sarah@example.com'

Program output:

Student emails:
sarah@example.com
harry@example.com
hermione@example.com
ron@example.com

This type of structure is exactly what we see in JSON data returned by web APIs.


5.5 Read JSON and install packages with Pip

What is JSON?

JSON (JavaScript Object Notation) is a data format commonly used to exchange data to and from a web server. This is typically a mix of lists and dictionaries — just like our previous examples.

{
    "number": 4,
    "students": [
        {"name": "Sarah Holderness", "email": "sarah@example.com"}
    ]
}

HTTP requests

When we make a web request from our program:

  1. Our program sends an HTTP request to the web server.
  2. The server returns an HTTP response containing the data (often in JSON format).

For example, api.open-notify.org/astros.json returns the people currently in the space in JSON format.

The requests package

To make HTTP requests, we need the requests package. This package is not in the Standard Library — it must be installed with pip (Python’s package installer).

pip — The Python package manager

pip is the Python package management tool. To install a package:

# Sur Mac/Linux
pip3 install requests

# Sur Windows
pip install requests

To see all installed packages:

pip list

To uninstall a package:

pip uninstall requests

You can also search for packages available on pypi.org (Python Package Index).

Use package requests

File: 05/demos/demos/space_people.py

# Note : il faut d'abord exécuter 'pip install requests'
import requests

people = requests.get('http://api.open-notify.org/astros.json')
json = people.json()

print(json)

print('The people currently in space are:')
for p in json['people']:
    print(p['name'])

Code analysis

  1. requests.get(url) sends an HTTP GET request to the URL and returns a response object.
  2. .json() converts the JSON content of the response into a Python dictionary/list.
  3. We iterate over json['people'] which is a list of dictionaries, and we display the name of each person.

5.6 Demo: Create a Python virtual environment

Why use a virtual environment?

Let’s imagine two Python projects:

  • Project A needs version 2.28 of the requests package.
  • Project B needs requests version 2.31.

If we install the packages globally (on the entire computer), the two projects would share the same version, which could break one of them.

The solution: a virtual environment (venv) — an isolated Python environment for each project, with its own packages and versions.

Create a virtual environment

# Créer un venv nommé 'venv' dans le dossier courant
python3 -m venv venv
  • -m venv: run module venv
  • The last venv: the name of the environment folder

This creates a venv folder in the project with the activation scripts.

Enable virtual environment

# Sur Mac/Linux
source venv/bin/activate

# Sur Windows
venv\Scripts\activate

Once enabled, we see (venv) at the start of the command line.

Install packages in venv

Once venv is enabled, pip install installs packages only in this environment:

pip install requests

Disable venv

deactivate

Share dependencies with requirements.txt

To share a list of installed packages:

pip freeze > requirements.txt

To reinstall them (for example on another computer):

pip install -r requirements.txt

5.7 Demo: Using the Open Weather Map API

In this demo, we will make requests to a weather API to display the current weather.

File: 05/demos/demos/weather.py

import requests

def get_weather_json(city):
    url = 'http://api.weatherapi.com/v1/current.json?key=YOUR_API_KEY&q=' + city + '&aqi=no'
    response = requests.get(url)
    weather_json = response.json()
    return weather_json

def get_current_temperature(json):
    temp = json.get('current').get('temp_f')
    return temp

def get_current_description(json):
    desc = json.get('current').get('condition').get('text')
    return desc

def main():
    city = 'Orlando'
    weather_json = get_weather_json(city)
    temp = get_current_temperature(weather_json)
    description = get_current_description(weather_json)

    print("Today's weather in", city, 'is', description, 'and', temp, 'degrees')

main()

Steps to use the API

  1. Register on weatherapi.com: create a free account to obtain an API key (API key). The API key is what authenticates our requests.

  2. Explore API Explorer: The “API Explorer” page shows how to construct the request URL with our key and the desired city.

  3. Request URL: URL contains our API key and location. The JSON response contains many fields; we are interested in current.temp_f (temperature in Fahrenheit) and current.condition.text (weather description).

  4. Chaining get(): to access nested data in JSON, you can chain several get() calls:

    temp = json.get('current').get('temp_f')
    

Example output:

Today's weather in Orlando is Sunny and 77 degrees

6. Functions

6.1 Functions

We have already used many functions. We can think of functions as mini-programs. Although it is not clear how they work internally, they return the expected results.

Functions used so far

FunctionDescription
print()Takes one or more strings and displays them in the console
input()Displays a prompt and returns the string entered by the user
int()Converts a number to an integer and returns it
float()Convert to decimal
str()Convert to string
len()Returns the length of a list or string
sum()Calculate the sum of a list
random.randint()Returns a random integer in a given range

You can define a function to do just about anything, and once defined, you can use it over and over again.

Define function

def greeting(name):
    print("Hello, " + name + "!")
  • The keyword def (short for “define”) begins the definition.
  • Followed by function name (greeting).
  • Then the parameters in parentheses (the values ​​to pass to the function) — here name.
  • The function body is indented below.

Call a function

name = input("Enter your name: ")
greeting(name)   # Appel de la fonction

Important: the function is not executed before being explicitly called. The order matters: you must define the function before calling it, just like you must declare a variable before using it.

Order of execution of a program

def greeting(name):          # 1) La définition est lue mais PAS exécutée
    print("Hello, " + name)

name = input("Enter your name: ")   # 2) Première ligne du programme principal
greeting(name)               # 3) La fonction est appelée, puis exécutée

Functions with return value

A function can return a value with the return keyword:

def add(a, b):
    result = a + b
    return result

total = add(5, 3)
print(total)   # 8

Parameters vs arguments

  • Parameter: the name of the variable in the function definition (name in def greeting(name)).
  • Argument: the concrete value passed during the call (greeting("Sarah") → “Sarah” is the argument).

Local variables and scope

Variables defined inside a function are local — they only exist within that function:

def calculate():
    result = 10 * 5   # Variable locale
    return result

# print(result)   # ERREUR : result n'existe pas ici
total = calculate()
print(total)   # OK

The main() function

A good practice is to define a main() function for the main program, in order to clearly separate utility functions from the main program:

def roll_dice():
    # ...
    return total

def main():
    # Programme principal ici
    result = roll_dice()
    print(result)

main()   # Appel du programme principal

6.2 Demo: Create a dice game

In this demo we will create a basic dice game where two players roll a pair of dice to see who wins.

File: 06/demos/demos/dice_game.py

import random

def roll_dice():
    dice_total = random.randint(1, 6) + random.randint(1, 6)
    return dice_total

def main():
    player1 = input("Enter player 1's name:\n")
    player2 = input("Enter player 2's name:\n")

    roll1 = roll_dice()
    roll2 = roll_dice()

    print(player1, 'rolled', roll1)
    print(player2, 'rolled', roll2)

    if roll1 > roll2:
        print(player1, 'wins!')
    elif roll2 > roll1:
        print(player2, 'wins!')
    else:
        print('You tie!')

main()

Why create a roll_dice() function?

Since the code for rolling the dice is the same for player 1 and player 2, this is a good candidate for a function. This avoids code duplication (DRY principle: Don’t Repeat Yourself).

Code analysis

  1. roll_dice():
  • Simulates the roll of two 6-sided dice with two calls to random.randint(1, 6).
  • Adds the two values for a total between 2 and 12.
  • Returns this total.
  1. main():
  • Requests the names of both players.
  • Call roll_dice() twice (one for each player).
  • Compares totals and displays winner.

Execution example:

Enter player 1's name: Sarah
Enter player 2's name: Lee
Sarah rolled 8
Lee rolled 5
Sarah wins!

7. Classes and Objects

7.1 Classes

As programs grow, it becomes impossible for a single person to understand all the complexity. To do very complex things — like developing robots or video games — it’s useful to think of code as objects.

Objects: state and behavior

In real life and in object-oriented programming (OOP — Object-Oriented Programming), objects have:

  • A state: the data it stores
  • A behavior: what it can do

Examples:

ObjectStateBehavior
Telephonemodel, color, storage capacityring, receive notifications, send
Dogname, breed, is he hungry?bark, whine, wag tail
Robot dogname, race, battery levelwalk, bark, wag tail

Class vs Instance/Object

  • A class (class) is a template (template or blueprint) for creating objects.
  • An instance or object is a concrete realization of this class.
Classe Robot_Dog  →  objet my_robot (une instance de Robot_Dog)

Define a class

class Robot_Dog:
    def __init__(self, name, breed):
        self.name = name
        self.breed = breed
    
    def bark(self):
        print(self.name, "says: Woof!")
    
    def wag_tail(self):
        print(self.name, "is wagging its tail!")
  • The keyword class followed by the name of the class (convention: PascalCase).
  • __init__: special method called constructor. It is automatically called when you create an object. It initializes the state of the object.
  • self: reference to the current instance. All method parameters start with self.
  • self.name: a property (property) or attribute of the object.
  • Other methods define the behavior of the object.

Create and use an object

# Créer une instance (objet) de Robot_Dog
my_robot = Robot_Dog("Rex", "Labrador")

# Accéder aux propriétés
print(my_robot.name)    # Rex
print(my_robot.breed)   # Labrador

# Appeler des méthodes
my_robot.bark()         # Rex says: Woof!
my_robot.wag_tail()     # Rex is wagging its tail!

You can create several instances:

robot1 = Robot_Dog("Rex", "Labrador")
robot2 = Robot_Dog("Buddy", "Poodle")

robot1.bark()   # Rex says: Woof!
robot2.bark()   # Buddy says: Woof!

Each object has its own state (name, breed) but shares the same behavior definition (methods).


7.2 Demo: Business Payroll with Classes

In this demo, we will create a Company class to manage its employees and calculate their weekly paychecks. We will also need an Employee class.

Employee.py file

File: 07/demos/demos/employee.py

class Employee:
    def __init__(self, fname, lname):
        self.fname = fname
        self.lname = lname

class SalaryEmployee(Employee):
    def __init__(self, fname, lname, salary):
        super().__init__(fname, lname)
        self.salary = salary
    
    def calculate_paycheck(self):
        return self.salary / 52
    
class HourlyEmployee(Employee):
    def __init__(self, fname, lname, weekly_hours, hourly_rate):
        super().__init__(fname, lname)
        self.weekly_hours = weekly_hours
        self.hourly_rate = hourly_rate

    def calculate_paycheck(self):
        return self.weekly_hours * self.hourly_rate
    
class CommissionEmployee(SalaryEmployee):
    def __init__(self, fname, lname, salary, sales_num, com_rate):
        super().__init__(fname, lname, salary)
        self.sales_num = sales_num
        self.com_rate = com_rate

    def calculate_paycheck(self):
        regular_salary = super().calculate_paycheck()
        total_commission = self.sales_num * self.com_rate
        return regular_salary + total_commission

company.py file

File: 07/demos/demos/company.py

from employee import Employee, SalaryEmployee, HourlyEmployee, CommissionEmployee

class Company:
    def __init__(self):
        self.employees = []
    
    def add_employee(self, new_employee):
        self.employees.append(new_employee)

    def display_employees(self):
        print('Current Employees:')
        for i in self.employees:
            print(i.fname, i.lname)
        print('-------------------')

    def pay_employees(self):
        print('Paying Employees:')
        for i in self.employees:
            print('Paycheck for:', i.fname, i.lname)
            print(f'Amount:  ${i.calculate_paycheck():,.2f}')
            print('---------------------------')

def main():
    my_company = Company()

    employee1 = SalaryEmployee('Sarah', 'Hess', 50000)
    my_company.add_employee(employee1)
    employee2 = HourlyEmployee('Lee', 'Smith', 25, 50)
    my_company.add_employee(employee2)
    employee3 = CommissionEmployee('Bob', 'Brown', 30000, 5, 200)
    my_company.add_employee(employee3)

    my_company.display_employees()
    my_company.pay_employees()

main()

Code analysis

Employee class (initial version):

  • __init__ receives fname, lname, and salary.
  • calculate_paycheck() returns salary / 52 (weekly salary if divided over 52 weeks).

Company Class:

  • Employees property: a list to store Employee objects.
  • add_employee(new_employee) method: add the employee to the list.
  • display_employees() method: loops and displays all employees.
  • pay_employees() method: loops and calculates/displays everyone’s paycheck.

Cross-file import:

from employee import Employee
  • employee (lower case): name of the .py file.
  • Employee (uppercase): class name.

f-strings with formatting:

print(f'Amount:  ${i.calculate_paycheck():,.2f}')
  • {value:,.2f} formats a float with commas as thousands separators and 2 decimal places.

Main program in main(): We define main() to clearly separate where the program starts.

Output:

Current Employees:
Sarah Hess
Lee Smith
Bob Brown
-------------------
Paying Employees:
Paycheck for: Sarah Hess
Amount:  $961.54
---------------------------
Paycheck for: Lee Smith
Amount:  $1,250.00
---------------------------
Paycheck for: Bob Brown
Amount:  $1,576.92
---------------------------

7.3 Class inheritance

In object-oriented programming, the relationship between objects is important. There are two types of relationships:

The Has-a relationship

An object has another object as a property.

Examples:

  • Our Company has Employee → we created a list of Employee objects as property of Company.
  • A Robot class has a Battery object.

The Is-a (Is-a) Relationship — Inheritance

A class is a more specific type of something else.

Examples:

  • RobotDog is a Robot
  • RobotCat is a Robot
  • SalaryEmployee is a Employee

The Is-a relationship is also called inheritance.

Terminology

TermSynonymsDescription
Base classParent class, superclassThe general class
Derived classChild class, subclassThe more specific class

How inheritance works

Inheritance allows you to create a hierarchy of classes that share properties and methods. Common behaviors are put in the parent class, and specific behaviors stay in the child classes.

Robot (classe parent)
├── walk()
├── manage_battery()
└── say_name()
    ├── RobotDog (classe enfant)
    │   ├── bark()
    │   └── eat_bacon()
    └── RobotCat (classe enfant)
        ├── meow()
        └── eat_fish()

Advantages:

  1. Code reuse: we write the common code only once in the parent class.
  2. Simplified maintenance: change common behavior in one place.
  3. Organization: The hierarchy reflects the actual relationships between objects.

Inheritance syntax

class Animal:
    def __init__(self, name):
        self.name = name
    
    def eat(self):
        print(self.name, "is eating.")

class Dog(Animal):   # Dog hérite de Animal
    def bark(self):
        print(self.name, "says Woof!")

class Cat(Animal):   # Cat hérite de Animal
    def meow(self):
        print(self.name, "says Meow!")
  • class Dog(Animal): Dog inherits from Animal (put in parentheses).
  • Dog automatically inherits all methods from Animal.

super().init()

When a child class has its own __init__, we call super().__init__() to call the parent constructor:

class SalaryEmployee(Employee):
    def __init__(self, fname, lname, salary):
        super().__init__(fname, lname)   # Appelle Employee.__init__
        self.salary = salary

super() refers to the parent class. This avoids duplicating common property initialization code.


7.4 Demo: Business payroll with inheritance

In this demo, we will use inheritance to add different types of employees. The company now has salary, hourly and commission employees.

The classes SalaryEmployee, HourlyEmployee and CommissionEmployee all inherit from the general class Employee.

Updated file: 07/demos/demos/employee.py (see full code in section 7.2)

Class SalaryEmployee

class SalaryEmployee(Employee):
    def __init__(self, fname, lname, salary):
        super().__init__(fname, lname)
        self.salary = salary
    
    def calculate_paycheck(self):
        return self.salary / 52
  • Inherits from Employee.
  • Adds salary property.
  • calculate_paycheck(): annual salary ÷ 52 weeks.

Class HourlyEmployee

class HourlyEmployee(Employee):
    def __init__(self, fname, lname, weekly_hours, hourly_rate):
        super().__init__(fname, lname)
        self.weekly_hours = weekly_hours
        self.hourly_rate = hourly_rate

    def calculate_paycheck(self):
        return self.weekly_hours * self.hourly_rate
  • Inherits from Employee.
  • Add weekly_hours and hourly_rate.
  • calculate_paycheck(): hours × hourly rate.

Class CommissionEmployee

class CommissionEmployee(SalaryEmployee):
    def __init__(self, fname, lname, salary, sales_num, com_rate):
        super().__init__(fname, lname, salary)
        self.sales_num = sales_num
        self.com_rate = com_rate

    def calculate_paycheck(self):
        regular_salary = super().calculate_paycheck()
        total_commission = self.sales_num * self.com_rate
        return regular_salary + total_commission
  • Inherits from SalaryEmployee (not from Employee directly).
  • Add sales_num (number of sales) and com_rate (commission rate).
  • calculate_paycheck(): regular salary + (number of sales × commission rate).
  • Use super().calculate_paycheck() to call the SalaryEmployee method.

Polymorphism

Note that each class has its own implementation of calculate_paycheck(). When pay_employees() calls i.calculate_paycheck() in a loop, Python automatically calls the correct version based on the actual type of the object. This is polymorphism.

for i in self.employees:
    print(f'Amount:  ${i.calculate_paycheck():,.2f}')
    # Appelle la bonne méthode selon le type (Salary, Hourly, ou Commission)

Usage in company.py:

my_company = Company()
employee1 = SalaryEmployee('Sarah', 'Hess', 50000)
employee2 = HourlyEmployee('Lee', 'Smith', 25, 50)
employee3 = CommissionEmployee('Bob', 'Brown', 30000, 5, 200)

8. Working with Files

8.1 Exceptions

Arrived at this point without errors? It’s amazing! Errors are part of programming — here’s how to deal with them.

Syntax errors (SyntaxError)

Syntax errors are caused by typos in the code. When the Python interpreter encounters such an error, it doesn’t know what we wanted to do.

# Exemple avec une parenthèse non appairée
print("Hello"
SyntaxError: '(' was never closed
  File "test.py", line 1
    print("Hello"
          ^

The error output shows the file, line number, and points exactly to the problem character — very useful for finding the error.

Exceptions (Exceptions)

Exceptions occur when the syntax is correct (Python knows what we want to do) but the operation fails at runtime.

Common examples:

# KeyError : clé inexistante dans un dictionnaire
acronyms = {'LOL': 'laugh out loud'}
print(acronyms['IDK'])   # KeyError: 'IDK'

# TypeError : opération sur des types incompatibles
age = "37" + 10   # TypeError: can only concatenate str (not "int") to str

# ValueError : valeur incorrecte
int("abc")   # ValueError: invalid literal for int() with base 10: 'abc'

# FileNotFoundError : fichier introuvable
open("nonexistent.txt")   # FileNotFoundError

# ZeroDivisionError : division par zéro
5 / 0   # ZeroDivisionError: division by zero

The try/except block

To catch an exception and prevent it from crashing the program, we use a try/except block:

try:
    print(acronyms['IDK'])
except:
    print("Error: key not found")

print("Program continues...")

Output:

Error: key not found
Program continues...

Without the try/except, the program would terminate on the error.

Try/except structure

try:
    # Code qui peut causer une erreur
    result = some_risky_operation()
except:
    # Code exécuté si une erreur survient
    print("An error occurred")

# Le programme continue ici dans tous les cas

This is similar to an if/else: try = “try to do this”, except = “if it fails, do this”.

Catch a specific type of exception

You can specify the type of exception to catch:

try:
    with open('acronyms.txt') as file:
        for line in file:
            if acronym in line:
                print(line)
except FileNotFoundError as e:
    print('File not found')
  • FileNotFoundError: only catches this error.
  • as e: assigns the exception to the variable e to access it if necessary.

We can chain several except to handle different types of errors:

try:
    # ...
except FileNotFoundError:
    print("File not found")
except KeyError:
    print("Key not found")
except Exception as e:
    print("Unexpected error:", e)

Why catch exceptions?

If you do not handle errors with try/except, an uncaught exception will crash the program. With a try/except block, we can handle the error gracefully and let the program continue running.


8.2 Read files

We have compiled a list of IT acronyms and their definitions in a text file. We want to create a program that allows the user to search for an acronym and display its definition.

Execution example:

What acronym would you like to look up? FIFO
FIFO - First In First Out

What acronym would you like to look up? FDAF
The acronym does not exist

Program steps

  1. Ask the user for an acronym (input)
  2. Open file for reading
  3. Loop over each line of the file
  4. Check if the line contains the desired acronym
  5. Show definition

File paths

Before reading/writing files, you need to tell Python where the file is located.

Absolute path: starts at the root of the file system.

# Mac/Linux
'/Users/sarah/Desktop/input.txt'

# Windows
'C:/Users/sarah/Desktop/input.txt'

Relative path: if the program is in the same folder as the file, we can use just the name:

'input.txt'   # Cherche dans le dossier courant

Open a file with with open()

The recommended way to open a file in Python is with with open():

with open('software_acronyms.txt') as file:
    for line in file:
        print(line)
  • open('filename') opens the file for reading (default 'r' mode).
  • with guarantees that the file will be closed automatically when exiting the block, even in case of an error.
  • as file names the file object file.
  • We loop over the file to read line by line.

Acronym search program

File: 08/demos/demos/acronyms-original.py

def find_acronym():
    look_up = input("What software acronym would you like to look up?\n")

    found = False
    try:
        with open('software_acronyms.txt') as file:
            for line in file:
                if look_up in line:
                    print(line)
                    found = True
                    break
    except FileNotFoundError as e:
        print('File not found')
        return

    if not found:
        print('The acronym does not exist')

def add_acronym():
    acronym = input('What acronym do you want to add?\n')
    definition = input('What is the definition?\n')
    with open('acronyms.txt', 'a') as file:
        file.write(acronym + ' - ' + definition + '\n')

def main():
    choice = input('Do you want to find(F) or add(A) an acronym?')
    if choice == 'F':
        find_acronym()
    elif choice == 'A':
        add_acronym()

main()

Important checks

  • The in operator checks if a string is contained within another: if look_up in line.
  • We use break to exit the loop as soon as we have found the acronym.
  • A Boolean variable found allows you to know if the acronym was found after the loop.

8.3 Demo: Writing to files

In this demo we will allow the user to add their own acronyms and definitions to the file.

File: 08/demos/demos/acronyms.py

def find_acronym(filename, acronym):
    try:
        with open(filename) as file:
            for line in file:
                if acronym in line:
                    print(line)
                    return line
    except FileNotFoundError as e:
        print('File not found')
        return False
    
    # L'acronyme n'a pas été trouvé après avoir parcouru tout le fichier
    print('The acronym does not exist')
    return False

def add_acronym(filename, acronym, definition):
    try:
        with open(filename, 'a') as file:
            file.write(f"{acronym} - {definition}\n")
            return True
    except OSError:
        print('Cannot open file for writing.')
    return False

if __name__ == "__main__":
    filename = 'software_acronyms.txt'
    choice = input('Do you want to find(F) or add(A) an acronym?')
    if choice == 'F':
        look_up = input("What software acronym would you like to look up?\n")
        find_acronym(filename, look_up)
    elif choice == 'A':
        acronym = input('What acronym do you want to add?\n')
        definition = input('What is the definition?\n')
        add_acronym(filename, acronym, definition)

File opening modes

When opening a file with open(), the second argument is mode:

FashionDescription
'r'Read only (default). The file must exist.
'w'Writing. Creates the file if it does not exist. OVERWRITE if existing.
'a'Addition (append). Appends to the end of the existing file.
'x'Exclusive creation. Fails if the file already exists.
'r+'Reading and writing.

To add content without deleting what exists, we use 'a' (append):

with open('software_acronyms.txt', 'a') as file:
    file.write("API - Application Programming Interface\n")

Warning: 'w' mode erases all existing content!

Write to file

The write() method writes a string to the file. We must add \n manually for line breaks:

with open('output.txt', 'w') as file:
    file.write("Hello, World!\n")
    file.write("Second line\n")

if name == “main

if __name__ == "__main__":
    # Code exécuté uniquement si ce fichier est lancé directement
    main()

This condition is true when the script is executed directly (not imported by another module). This is a good practice for reusable Python scripts.


8.4 File handling

Python has several built-in modules for file manipulation:

ModuleDescription
osSystem functions: create folders, list, move
shutilHigh-level file/folder operations
pathlibObject-Oriented Path Manipulation

The os module

File: 08/demos/demos/file_cleanup.py

import os

folder_original = '/Users/sarah/Desktop/'
folder_destination = '/Users/sarah/Desktop/CleanedUp/'

os.mkdir(folder_destination)

for entry in os.scandir(folder_original):
    location_original = os.path.join(folder_original, entry.name)
    location_destination = os.path.join(folder_destination, entry.name)
    
    if os.path.isfile(location_original):
        os.rename(location_original, location_destination)

Key functions of the os module

import os

# Créer un nouveau dossier
os.mkdir('/Users/sarah/Desktop/CleanedUp')

# Lister le contenu d'un dossier
for entry in os.scandir('/Users/sarah/Desktop'):
    if os.path.isfile(entry):
        print("File:", entry.name)
    elif os.path.isdir(entry):
        print("Directory:", entry.name)

# Construire un chemin de façon portable (marche sur tous les OS)
path = os.path.join('/Users/sarah', 'Desktop', 'file.txt')
# Résultat : '/Users/sarah/Desktop/file.txt'

# Obtenir les attributs d'un fichier
size = os.path.getsize('file.txt')       # Taille en octets
mtime = os.path.getmtime('file.txt')     # Date de modification

# Vérifications
os.path.isfile('file.txt')    # True si c'est un fichier
os.path.isdir('my_folder')    # True si c'est un dossier
os.path.exists('file.txt')    # True si existe

# Déplacer/renommer un fichier
os.rename('old_path/file.txt', 'new_path/file.txt')

# Dossier personnel de l'utilisateur (cross-platform)
home = os.path.expanduser("~/Desktop")

Best practice: always use os.path.join() to construct paths — this works on Windows (\ separator) and Mac/Linux (/ separator).

The shutil module

shutil offers higher level functions:

import shutil

# Déplacer un fichier
shutil.move('source/file.txt', 'destination/')

# Copier un fichier
shutil.copy('source.txt', 'destination.txt')

# Supprimer un dossier entier (avec tout son contenu)
shutil.rmtree('folder_to_delete')

8.5 Demo: File Organization

In this demo, we will improve our file cleaning program by organizing desktop files into subfolders according to their extension: Images, Documents, and Archives.

We will also use ChatGPT to write the program and then analyze the output to verify that it is correct.

This exercise illustrates two important skills:

  1. Analyze existing code — in the professional world, we are often required to read and understand code written by others.
  2. Verify AI-generated code — AI can be used to create solutions, but you always need to verify that the solution is correct.

Prompt ChatGPT used:

“Please write a Python 3 application that will organize the files on my desktop into subfolders based on the file extensions, such as images, documents, and zip archives.”

File: 08/demos/demos/organize.py

import os
import shutil

# Path of the desktop folder
desktop_path = os.path.expanduser("~/Desktop")

# Dictionary containing the folder names and their corresponding file extensions
folders = {
    "Images": [".jpeg", ".jpg", ".png", ".gif"],
    "Documents": [".doc", ".docx", ".pdf", ".txt"],
    "Archives": [".zip", ".rar"]
}

# Create the subfolders if they don't exist
for folder_name in folders:
    folder_path = os.path.join(desktop_path, folder_name)
    if not os.path.exists(folder_path):
        os.makedirs(folder_path)

# Move files to the corresponding subfolder
for file_name in os.listdir(desktop_path):
    original_file_path = os.path.join(desktop_path, file_name)
    if os.path.isfile(original_file_path):
        for folder_name, extensions in folders.items():
            for extension in extensions:
                if file_name.endswith(extension):
                    destination_folder = os.path.join(desktop_path, folder_name)
                    shutil.move(original_file_path, destination_folder)

Analysis of generated code

1. Importing modules:

import os
import shutil

os for system operations, shutil for moving files.

2. Path to office:

desktop_path = os.path.expanduser("~/Desktop")

os.path.expanduser("~") returns the user’s home folder portablely.

3. Extension dictionary:

folders = {
    "Images": [".jpeg", ".jpg", ".png", ".gif"],
    "Documents": [".doc", ".docx", ".pdf", ".txt"],
    "Archives": [".zip", ".rar"]
}

Each key is the name of the subfolder, and each value is a list of matching extensions.

4. Creation of subfolders:

for folder_name in folders:
    folder_path = os.path.join(desktop_path, folder_name)
    if not os.path.exists(folder_path):
        os.makedirs(folder_path)

We iterate over the keys of the folders dictionary, we check if the folder already exists (os.path.exists), and we create it only if it does not exist (os.makedirs).

5. Move files:

for file_name in os.listdir(desktop_path):
    original_file_path = os.path.join(desktop_path, file_name)
    if os.path.isfile(original_file_path):
        for folder_name, extensions in folders.items():
            for extension in extensions:
                if file_name.endswith(extension):
                    destination_folder = os.path.join(desktop_path, folder_name)
                    shutil.move(original_file_path, destination_folder)
  • os.listdir() lists all files and folders in a directory.
  • We check that it is indeed a file (not a folder) with os.path.isfile().
  • We iterate over the categories and their extensions.
  • file_name.endswith(extension) checks if the file has this extension.
  • shutil.move() moves the file to the appropriate subfolder.

Result: files .jpg, .png, etc. are removed. go to Images/, the .pdf, .docx to Documents/, and the .zip to Archives/.


9. General Summary

This Python 3 Fundamentals training covers all the bases necessary to program in Python. Here are the essential concepts mastered:

Fundamental concepts

ConceptModuleDescription
Variables and primitive types2int, float, str, bool
Arithmetic operators2+, -, *, /, //, %, **
Input/Output2input(), print(), f-strings
Type Conversions2int(), float(), str()
Conditionals3if, elif, else, logical operators and, or
Comparators3==, !=, <, >, <=, >=
Modules (import)3import random, random.randint(), random.choice()
Lists4creation, append(), remove(), pop(), index
for loops4iterate over lists, range(), break
Dictionaries5key-value pairs, get(), items(), del
JSON5data format, response.json()
Pip and packages5pip install, virtual environments (venv)
Functions6def, parameters, return, scope
Classes and OOP7class, __init__, properties, methods, inheritance
Exceptions8try/except, SyntaxError, KeyError, FileNotFoundError
Reading/Writing Files8open(), modes r/w/a, with, loop on lines
File handling8os, shutil, os.path.join(), os.scandir()

Programs built during training

ProgramFileIllustrated concepts
Tax calculatortax.pyVariables, operations, print
Age calculatordecades.pyinput, int(), //, %
Rock, Paper, Scissorsrock_paper_scissors.pyif/elif/else, comparators
Random PPCrock_paper_scissors_random.pyimport random, random.choice()
Total expensesexpenses.pyLists, for loops, sum()
Loan Calculatorloan.pyrange(), break, comments
Movie timesmovie_schedule.pyDictionaries, get(), loop over dict
Nested contactscontacts.pyJSON structures, dictionary lists
People in spacespace_people.pyrequests, HTTP, JSON
Weatherweather.pyAPI, functions, chained get()
Dice gamedice_game.pyFunctions, return, randint
Business Payrollemployee.py, company.pyClasses, OOP, inheritance, polymorphism
Acronym Searchacronyms.pyRead/write files, exceptions
File Cleanupfile_cleanup.pyos, scandir, rename
File organizationorganize.pyos, shutil, endswith, ChatGPT

Search Terms

python · fundamentals · foundations · data · analysis · engineering · analytics · function · dictionary · class · functions · inheritance · lists · types · environment · list · range · virtual · calculator · classes · dictionaries · exceptions · game · install

Interested in this course?

Contact us to book it or get a custom training plan for your team.