Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
93 commits
Select commit Hold shift + click to select a range
d7860a4
create a dir for my exercises and a .py file for exercise 1
HassanOHOsman Dec 2, 2025
c6edd33
provide 2 solutions to exercise 1
HassanOHOsman Dec 2, 2025
bbca608
rename file
HassanOHOsman Dec 2, 2025
597f47e
create file to exercise 1
HassanOHOsman Dec 2, 2025
adec5ea
add exercise 1 question
HassanOHOsman Dec 2, 2025
c202adf
answer to Q 1 of exercises
HassanOHOsman Dec 2, 2025
4917fe7
create venv
HassanOHOsman Dec 2, 2025
ab0e5d5
install mypy
HassanOHOsman Dec 2, 2025
b0143fd
create a test file to test some py code
HassanOHOsman Dec 2, 2025
5c7d52c
adding type annotation to the function def to avoid getting errors wh…
HassanOHOsman Dec 2, 2025
6803aed
re-add type annotation to function def
HassanOHOsman Dec 2, 2025
dd86ef8
delete the test file
HassanOHOsman Dec 2, 2025
9df4222
create a .py file for exercise 3
HassanOHOsman Dec 2, 2025
bf4f92c
type annotate open_account function return
HassanOHOsman Dec 3, 2025
0b58dee
type anno. open_account arguments
HassanOHOsman Dec 3, 2025
e133ed6
add a return line to function open-account
HassanOHOsman Dec 3, 2025
0692d80
type anno. return for function sum_balance
HassanOHOsman Dec 3, 2025
93e8215
type anno. the argument accounts of function sum_balances
HassanOHOsman Dec 3, 2025
eaa2fa4
type annotate the argument and return for function format_pence_as_st…
HassanOHOsman Dec 3, 2025
b7f3ae2
adding the missing third argument: "balances" to the 2 open_account …
HassanOHOsman Dec 3, 2025
530b650
updated all the int values to float
HassanOHOsman Dec 3, 2025
b55e70c
updating type anno. and making a few changes
HassanOHOsman Dec 3, 2025
ccce3db
correcting syntax error in sum_balances func and the name of the 1st …
HassanOHOsman Dec 3, 2025
bb87b72
fixed bugs in the 2 open_account fuc calls at the bottom
HassanOHOsman Dec 3, 2025
ce70769
corrected the name bug for the format_pence_as_string call at the bottom
HassanOHOsman Dec 3, 2025
a70ac33
create .py file for exercise 4
HassanOHOsman Dec 3, 2025
550f320
add solution to problem 4
HassanOHOsman Dec 3, 2025
ee4aae2
create .py file for exercise 5
HassanOHOsman Dec 3, 2025
dc9fa85
add a question to problem 5
HassanOHOsman Dec 3, 2025
23cf5c5
create a new function as per exercise 5 requirments
HassanOHOsman Dec 3, 2025
a6564a3
explaing the 2 errors that associated with the new created function
HassanOHOsman Dec 3, 2025
9485080
create .py file to store exercise 6 work
HassanOHOsman Dec 3, 2025
b86a9a4
add solution to Q 6
HassanOHOsman Dec 3, 2025
dec7dc1
create .py file to store answers for Q7
HassanOHOsman Dec 3, 2025
6306f1a
add the Q
HassanOHOsman Dec 3, 2025
ddaf3fc
update the Q
HassanOHOsman Dec 3, 2025
421d9b1
re-order code
HassanOHOsman Dec 3, 2025
ecacbcd
importing the date module from datetime library
HassanOHOsman Dec 3, 2025
0a0fc91
adding "date_of_birth" attribute to "Person" class
HassanOHOsman Dec 3, 2025
a7955e3
updating addition of DOB as attribute
HassanOHOsman Dec 3, 2025
079a209
removing the age attribute from Person class
HassanOHOsman Dec 3, 2025
64fa3d7
updating the date_of_birth type as date
HassanOHOsman Dec 3, 2025
0621a7a
updated is_adult function to incorporate the new attribute
HassanOHOsman Dec 3, 2025
c86cb07
update to the is_adult function
HassanOHOsman Dec 3, 2025
6e8289f
na
HassanOHOsman Dec 3, 2025
e67ecc2
update the imran instance to reflect theattributes update
HassanOHOsman Dec 3, 2025
37a29f0
added a return type for the is_adult function
HassanOHOsman Dec 3, 2025
0e15f42
create .py file for exercise 8
HassanOHOsman Dec 4, 2025
8e1c160
imprt dataclass module from its library
HassanOHOsman Dec 4, 2025
dbe6de6
reconstructing the person class as per @dataclass
HassanOHOsman Dec 4, 2025
315c87a
add question 8 as a comment
HassanOHOsman Dec 4, 2025
a790f41
indenting the is_adult fuc so that it's considered part of the Person…
HassanOHOsman Dec 4, 2025
5082b38
housekeeping and removing extra spaces
HassanOHOsman Dec 4, 2025
e25ff74
create .py file with question 9
HassanOHOsman Dec 4, 2025
8bc0681
rearranging
HassanOHOsman Dec 4, 2025
d4ab965
added "age" field and updated class instances accodingly
HassanOHOsman Dec 4, 2025
7a430c1
create .py file for question 10
HassanOHOsman Dec 4, 2025
68993f5
add question 10
HassanOHOsman Dec 4, 2025
d276be9
change type anno. of "person.preferred_operating_system" to List[str]
HassanOHOsman Dec 4, 2025
70bc59a
renamed preferred_operating_system to preferred_operating_systems sin…
HassanOHOsman Dec 4, 2025
1eae1bb
adding a closing bracket to the list
HassanOHOsman Dec 4, 2025
45a6b7c
updated find_possible_laptops func to reflect the change to the type …
HassanOHOsman Dec 4, 2025
665b5d3
add question 11 as a comment
HassanOHOsman Dec 4, 2025
27fb6c5
update question 11
HassanOHOsman Dec 4, 2025
9cfc190
created a list of laptops avaiable to borrow from a library
HassanOHOsman Dec 4, 2025
017bce3
create classes: Laptop & Person via dataclass
HassanOHOsman Dec 4, 2025
0cac4f2
update values for laptop instances
HassanOHOsman Dec 4, 2025
6b1fc1e
create a person builder function
HassanOHOsman Dec 4, 2025
da93203
updating the person_builder func
HassanOHOsman Dec 4, 2025
12c6e38
convert ageinprson_builder func back to int
HassanOHOsman Dec 4, 2025
3022a19
testing person_builder func output by printing to console
HassanOHOsman Dec 4, 2025
e981618
allowing OS to be in lowercase too
HassanOHOsman Dec 4, 2025
2702dd9
updating code to validate types
HassanOHOsman Dec 4, 2025
b0de1ee
updated person_builder func validation for fields
HassanOHOsman Dec 4, 2025
f073259
remove type checking/valdiation lines as they are not working
HassanOHOsman Dec 5, 2025
1a0f28f
adding an OS with a limited list of avaible options
HassanOHOsman Dec 5, 2025
4a3d056
update rest of code as per enums importation
HassanOHOsman Dec 5, 2025
b1e5f1d
moving OS class at the top so OS field erro oin laptop class is avoided
HassanOHOsman Dec 5, 2025
eb1be83
add type validation measures
HassanOHOsman Dec 5, 2025
6c155a8
CREATE AND UPDATE LAPTOP COUNTER FUNCTION
HassanOHOsman Dec 5, 2025
b469b8d
add a helper function parse_os_input to handle a variety of ways end …
HassanOHOsman Dec 5, 2025
5c05376
update counter function to handle different cases as per number of la…
HassanOHOsman Dec 5, 2025
6cf094f
improve readability of output for counter OS
HassanOHOsman Dec 5, 2025
60782dd
input user message when there are more than a laptop of their chosen OS
HassanOHOsman Dec 5, 2025
275feb8
corrected laptop_counter func
HassanOHOsman Dec 5, 2025
5c49864
create OS counter to find out if more OS other than end user's preffe…
HassanOHOsman Dec 5, 2025
8cd2513
improve more_avaiable_function
HassanOHOsman Dec 5, 2025
25307d4
create .py file for exercise 12
HassanOHOsman Dec 8, 2025
43db6cf
add Q12 to the .py file
HassanOHOsman Dec 8, 2025
ff5238e
add prediction
HassanOHOsman Dec 8, 2025
40d209b
comment problematic lines
HassanOHOsman Dec 8, 2025
793653a
create a .gitignore file to ignore .venv dir due to its so many files
HassanOHOsman Jan 14, 2026
be69676
ignoring all .venv files
HassanOHOsman Jan 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions prep-exercises/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.venv

24 changes: 24 additions & 0 deletions prep-exercises/exercise_eight.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#Write a Person class using @datatype which uses a datetime.date for date of birth, rather than an
#int for age.

#Re-add the is_adult method to it.


from datetime import date
from dataclasses import dataclass

@dataclass
class Person:
name: str
date_of_birth: date
preferred_operating_system: str

def is_adult(self) ->bool:
age_in_days = (date.today() - self.date_of_birth).days
age_in_years = age_in_days / 365.2425
return age_in_years >= 18



imran = Person("Imran", date(2003,12, 3), "Ubuntu")
print(imran.is_adult())
122 changes: 122 additions & 0 deletions prep-exercises/exercise_eleven.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#Write a program which:

#1.Already has a list of Laptops that a library has to lend out.
#2.Accepts user input to create a new Person - it should use the input function to read a person’s
#name, age, and preferred operating system.
#3.Tells the user how many laptops the library has that have that operating system.
#4.If there is an operating system that has more laptops available, tells the user that if they’re willing to
#accept that operating system they’re more likely to get a laptop.

#You should convert the age and preferred operating system input from the user into more constrained
#types as quickly as possible, and should output errors to stderr and terminate the program with a non-
#zero exit code if the user input bad values.

from dataclasses import dataclass
import sys
from enum import Enum

class operatingSystem(Enum):
CHROMEOS = "ChromeOS"
WINDOWS = "Windows"
MACOS = "macOS"
LINUX = "Linux"
ARCH = "Arch Linux"
UBUNTU = "Ubuntu"



@dataclass(frozen=True)
class Person:
name: str
age: int
preferred_operating_system: str


@dataclass(frozen=True)
class Laptop:
id: int
manufacturer: str
model: str
screen_size_in_inches: float
operating_system: operatingSystem



laptops = [
Laptop(id=1, manufacturer="HP", model="Chromebook Plus 514", screen_size_in_inches=14, operating_system=operatingSystem.CHROMEOS),
Laptop(id=2, manufacturer="Microsoft", model="XPS", screen_size_in_inches=13.8, operating_system=operatingSystem.WINDOWS),
Laptop(id=3, manufacturer="Apple", model="MacBook Air", screen_size_in_inches=15, operating_system=operatingSystem.MACOS),
Laptop(id=4, manufacturer="Lenovo", model="ThinkPad X220", screen_size_in_inches=12.5, operating_system=operatingSystem.LINUX),
Laptop(id=5, manufacturer="Dell", model="XPS", screen_size_in_inches=13.7, operating_system=operatingSystem.ARCH),
Laptop(id=6, manufacturer="Dell", model="XPS", screen_size_in_inches=10.4, operating_system=operatingSystem.ARCH),
Laptop(id=7, manufacturer="Dell", model="XPS", screen_size_in_inches=15.5, operating_system=operatingSystem.UBUNTU),
Laptop(id=8, manufacturer="Dell", model="XPS", screen_size_in_inches=15, operating_system=operatingSystem.UBUNTU),
Laptop(id=9, manufacturer="Apple", model="MacBook", screen_size_in_inches=13.3, operating_system=operatingSystem.MACOS),
]


name_input = input("What's your name? ")
if not name_input.isalpha():
print("Name must contain letters only!")
sys.exit(1)

try:
age_input = int(input("What's your age? "))
except ValueError:
print("Enter a numeric value for the age!")
sys.exit(1)


def parse_os_input(user_input: str) -> operatingSystem:
clean = user_input.lower().replace(" ", "")

for os in operatingSystem:
if os.value.lower().replace(" ", "") == clean:
return os
print("Invalid operating system!", file=sys.stderr)
sys.exit(1)

preferred_operating_system_input = parse_os_input(input("What's your preferred operating system? "))



def person_builder(name_input: str, age_input:int, preferred_operating_system_input:str) ->Person:

return Person(name_input, age_input, preferred_operating_system_input)



def laptops_counter(preferred_operating_system_input:str) ->int:
sum = 0
for laptop in laptops:
if preferred_operating_system_input == laptop.operating_system:
sum += 1
user_os = preferred_operating_system_input.value
if sum == 1:
return f"There is {sum} laptop with {user_os} operating system"
elif sum > 1:
return f"There are {sum} laptops with {user_os} operating system"

print(laptops_counter(preferred_operating_system_input))


user_os = preferred_operating_system_input

def more_available_os(user_os: operatingSystem):

os_counter = {}
for laptop in laptops:
os_counter[laptop.operating_system] = os_counter.get(laptop.operating_system, 0) + 1

max_count = max(os_counter.values())

user_os_count = os_counter.get(user_os, 0)

if user_os_count < max_count:
most_available_os = max(os_counter, key=os_counter.get)
print(f"If you’re open to using {most_available_os.value} operating system, you’ll have a better chance of getting a laptop.”")


print(more_available_os(preferred_operating_system_input))


46 changes: 46 additions & 0 deletions prep-exercises/exercise_five.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Add the is_adult code to the file you saved earlier.

# Run it through mypy - notice that no errors are reported - mypy
# understands that Person has a property named age so is happy
# with the function.

# Write a new function in the file that accepts a Person as a
# parameter and tries to access a property that doesn’t exist. Run
# it through mypy and check that it does report an error.


class Person:
def __init__(self, name: str, age: int, preferred_operating_system: str):
self.name = name
self.age = age
self.preferred_operating_system = preferred_operating_system

imran = Person("Imran", 22, "Ubuntu")
print(imran.name)
print(imran.address)

eliza = Person("Eliza", 34, "Arch Linux")
print(eliza.name)
print(eliza.address)


def is_adult(person: Person) -> bool:
return person.age >= 18

print(is_adult(imran))



# New function: "is_engineer" takes "Person" as a parameter and tries to access "profession" - a property that does not exist.
def is_engineer(person: Person) -> bool:
return person.profession == "Engineer"

print(is_engineer(eliza))

# After running through mypy, 2 errors related to the new function were reported:
# 1) exercise_five.py:36: error: Returning Any from function declared to return "bool" [no-any-return]
# since person does not have "profession" as attribute and thus its type is unknown, thus this function could be returning any type. Hence the error above.
# 2) exercise_five.py:36: error: "Person" has no attribute "profession" [attr-defined]
# The error above simply stating that attribute "profession" does not exist in the class "Person"


20 changes: 20 additions & 0 deletions prep-exercises/exercise_four.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
class Person:
def __init__(self, name: str, age: int, preferred_operating_system: str):
self.name = name
self.age = age
self.preferred_operating_system = preferred_operating_system

imran = Person("Imran", 22, "Ubuntu")
print(imran.name)
print(imran.address)

eliza = Person("Eliza", 34, "Arch Linux")
print(eliza.name)
print(eliza.address)

# Save the above code to a file, and run it through mypy.

#Read the error, and make sure you understand what it’s telling you.

# The error message simply says that the class: Person does not have "address" as an attribute.
# Therefore, the instances of the class: Person can not inheret an attribute that does not exist.
29 changes: 29 additions & 0 deletions prep-exercises/exercise_nine.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from dataclasses import dataclass
from typing import List

@dataclass(frozen=True)
class Person:
name: str
#Add "age" attribute
age: int
children: List["Person"]

#Add "age" field and thier respective values to "fatma" and "aisha" - instances of class "Person"
fatma = Person(name="Fatma", age=14, children=[])
aisha = Person(name="Aisha",age=22, children=[])

##Add "age" field and its values to "imran" - instance of class "Person"
imran = Person(name="Imran", age=44, children=[fatma, aisha])

def print_family_tree(person: Person) -> None:
print(person.name)
for child in person.children:
print(f"- {child.name} ({child.age})")

print_family_tree(imran)


#Fix the above code so that it works. You must not change the print on line 17 - we do want to print the
#children’s ages. (Feel free to invent the ages of Imran’s children.)


11 changes: 11 additions & 0 deletions prep-exercises/exercise_one.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

def double(value):
return value * 2

print(double("22"))


# Predict what double("22") will do. Then run the code and check. Did it do what you expected? Why did it return the value it did?

# Initial prediction was that a type coercion may take place and string "22" will convert to integer 22 and thus the function returns 44.
# After running the code, I now know that it did not do what i expected. It duplicated/repeated the string and returned 2222.
28 changes: 28 additions & 0 deletions prep-exercises/exercise_seven.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#Change the Person class to take a date of birth (using the standard library’s datetime.date class) and
#store it in a field instead of age.

#Update the is_adult method to act the same as before.

from datetime import date


class Person:
def __init__(self, name: str, date_of_birth: date, preferred_operating_system: str):
self.name = name
self.preferred_operating_system = preferred_operating_system
#Add "date_of_birth" attribute to the "Person" class
self.date_of_birth = date_of_birth

def is_adult(self) ->bool:
age_in_days = (date.today() - self.date_of_birth).days
age_in_years = age_in_days / 365.2425
return age_in_years >= 18





imran = Person("Imran", date(2003,12, 3), "Ubuntu")
print(imran.is_adult())


6 changes: 6 additions & 0 deletions prep-exercises/exercise_six.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#Think of the advantages of using methods instead of free functions. Write them down in your notebook.

# Easy and direct to data and thus more efficient when working on them.
# it's more reusable since all instances of a class inheret those methods defined in it automatically.
# you'll be less prone to make mistakes when using methods as part of a class/isntance of it as opposed to a free function attempting to aceess the class data.
# code is more organised and readable when methods are part of a class as opposed to when they're just free functions.
56 changes: 56 additions & 0 deletions prep-exercises/exercise_ten.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
from dataclasses import dataclass
from typing import List

@dataclass(frozen=True)
class Person:
name: str
age: int
preferred_operating_systems: List[str]


@dataclass(frozen=True)
class Laptop:
id: int
manufacturer: str
model: str
screen_size_in_inches: float
operating_system: str


def find_possible_laptops(laptops: List[Laptop], person: Person) -> List[Laptop]:
possible_laptops = []
for laptop in laptops:
for item in person.preferred_operating_systems:
if laptop.operating_system == item:
possible_laptops.append(laptop)
return possible_laptops


people = [
Person(name="Imran", age=22, preferred_operating_systems=["Ubuntu", "Arch Linux", "macOS"]),
Person(name="Eliza", age=34, preferred_operating_systems=["Arch Linux", "macOS", "Ubuntu"]),
]

laptops = [
Laptop(id=1, manufacturer="Dell", model="XPS", screen_size_in_inches=13, operating_system="Arch Linux"),
Laptop(id=2, manufacturer="Dell", model="XPS", screen_size_in_inches=15, operating_system="Ubuntu"),
Laptop(id=3, manufacturer="Dell", model="XPS", screen_size_in_inches=15, operating_system="ubuntu"),
Laptop(id=4, manufacturer="Apple", model="macBook", screen_size_in_inches=13, operating_system="macOS"),
]

for person in people:
possible_laptops = find_possible_laptops(laptops, person)
print(f"Possible laptops for {person.name}: {possible_laptops}")


#Try changing the type annotation of Person.preferred_operating_system from str to List[str].

#Run mypy on the code.

#It tells us different places that our code is now wrong, because we’re passing values of the wrong type.

#We probably also want to rename our field - lists are plural. Rename the field to preferred_operating_systems.

#Run mypy again.

#Fix all of the places that mypy tells you need changing. Make sure the program works as you’d expect.
40 changes: 40 additions & 0 deletions prep-exercises/exercise_three.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#Do not run the following code.

#This code contains bugs related to types. They are bugs mypy can catch.

#Read this code to understand what it’s trying to do. Add type annotations to the method parameters and
#return types of this code. Run the code through mypy, and fix all of the bugs that show up. When you’re
#confident all of the type annotations are correct, and the bugs are fixed, run the code and check it works.

from typing import Dict

def open_account(balances: Dict[str, int], name: str, amount: int) ->None:
balances[name] = amount

def sum_balances(accounts: Dict[str, int]) ->int:
total = 0
for name, pence in accounts.items():
print(f"{name} had balance {pence}")
total += pence
return total

def format_pence_as_string(total_pence: int) ->str:
if total_pence < 100:
return f"{total_pence}p"
pounds = int(total_pence / 100)
pence = total_pence % 100
return f"£{pounds}.{pence:02d}"

balances = {
"Sima": 700,
"Linn": 545,
"Georg": 831,
}

open_account(balances, "Tobi", 9)
open_account(balances, "Olya", 7)

total_pence = sum_balances(balances)
total_string = format_pence_as_string(total_pence)

print(f"The bank accounts total {total_string}")
Loading