Skip to content

Commit 4cd664e

Browse files
London | 2026-mar-sdc | beko | Sprint 5 | prep exercises
complete sprint 5 exercises
1 parent d3857c2 commit 4cd664e

9 files changed

Lines changed: 409 additions & 0 deletions

File tree

prep exercises/checking_mypy.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
2+
3+
def open_account(balances: dict[str, int], name: str, amount: int) -> None:
4+
balances[name] = amount
5+
6+
def sum_balances(accounts: dict[str, int]) -> int:
7+
total = 0
8+
for name, pence in accounts.items():
9+
print(f"{name} had balance {pence}")
10+
total += pence
11+
return total
12+
13+
def format_pence_as_string(total_pence: int) -> str:
14+
if total_pence < 100:
15+
return f"{total_pence}p"
16+
pounds = int(total_pence / 100)
17+
pence = total_pence % 100
18+
return f"£{pounds}.{pence:02d}"
19+
20+
balances: dict[str, int] = {
21+
"Sima": 700,
22+
"Linn": 545,
23+
"Georg": 831,
24+
}
25+
26+
open_account(balances, "Tobi", 913)
27+
open_account(balances, "Olya", 713)
28+
29+
total_pence = sum_balances(balances)
30+
total_string = format_pence_as_string(total_pence)
31+
32+
print(f"The bank accounts total {total_string}")

prep exercises/dataclass.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
2+
3+
from dataclasses import dataclass
4+
from datetime import date
5+
6+
@dataclass(frozen=True)
7+
class Person:
8+
name: str
9+
birth_day: date
10+
preferred_OS: str
11+
12+
13+
def is_adult(self):
14+
today = date.today()
15+
age = today.year - self.birth_day.year
16+
17+
if (today.month, today.day) < (self.birth_day.month, self.birth_day.day):
18+
age -= 1
19+
return age >= 18
20+
21+
22+
beko = Person("Beko", date(2005, 2, 17), "Linux")
23+
print(beko.is_adult())
24+
25+
noor = Person("Noor", date(2015, 2, 17), "Linux")
26+
print(noor.is_adult())

prep exercises/double.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
2+
def double (num):
3+
return num * 2
4+
5+
print(double("22"))
6+
7+
# Predication
8+
# Did it do what you expected?
9+
# No, it didn't
10+
#
11+
# Why did it return the value it did?
12+
# because there is a mistype in the function, it should take a number but the argument is string
13+
#
14+
15+
def double_the_number(num):
16+
return num * 3
17+
18+
print(double_the_number(5))

prep exercises/enums.py

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
from dataclasses import dataclass
2+
from enum import Enum
3+
from typing import List
4+
import sys
5+
6+
7+
class OperatingSystem(Enum):
8+
MACOS = "macOS"
9+
ARCH = "Arch Linux"
10+
UBUNTU = "Ubuntu"
11+
12+
13+
@dataclass(frozen=True)
14+
class Person:
15+
name: str
16+
age: int
17+
preferred_operating_system: OperatingSystem
18+
19+
20+
@dataclass(frozen=True)
21+
class Laptop:
22+
id: int
23+
manufacturer: str
24+
model: str
25+
screen_size_in_inches: float
26+
operating_system: OperatingSystem
27+
28+
29+
# Existing inventory list
30+
laptops = [
31+
Laptop(
32+
id=1,
33+
manufacturer="Dell",
34+
model="XPS",
35+
screen_size_in_inches=13,
36+
operating_system=OperatingSystem.ARCH,
37+
),
38+
Laptop(
39+
id=2,
40+
manufacturer="Dell",
41+
model="XPS",
42+
screen_size_in_inches=15,
43+
operating_system=OperatingSystem.UBUNTU,
44+
),
45+
Laptop(
46+
id=3,
47+
manufacturer="Dell",
48+
model="XPS",
49+
screen_size_in_inches=15,
50+
operating_system=OperatingSystem.UBUNTU,
51+
),
52+
Laptop(
53+
id=4,
54+
manufacturer="Apple",
55+
model="macBook",
56+
screen_size_in_inches=13,
57+
operating_system=OperatingSystem.MACOS,
58+
),
59+
]
60+
61+
62+
def get_user_input() -> Person:
63+
name = input("Enter your name: ").strip()
64+
if not name:
65+
print("Error: Name cannot be empty.", file=sys.stderr)
66+
sys.exit(1)
67+
68+
# 1. check the person's age is valid
69+
try:
70+
age = int(input("Enter your age: "))
71+
if age < 0:
72+
raise ValueError
73+
except ValueError:
74+
print("Error: Age must be a positive whole number.", file=sys.stderr)
75+
sys.exit(1)
76+
77+
# 2. give the person a list of valid Operating Systems to choose from
78+
print("\nAvailable Operating Systems:")
79+
for os_option in OperatingSystem:
80+
print(f"- {os_option.value}")
81+
82+
os_input = input("Enter your preferred operating system: ").strip()
83+
84+
# Try to match the user string to a valid Enum value
85+
preferred_os = None
86+
for os_option in OperatingSystem:
87+
if os_option.value.lower() == os_input.lower():
88+
preferred_os = os_option
89+
break
90+
91+
if preferred_os is None:
92+
print(f"Error: '{os_input}' is not a valid operating system.", file=sys.stderr)
93+
sys.exit(1)
94+
95+
return Person(name=name, age=age, preferred_operating_system=preferred_os)
96+
97+
98+
def main():
99+
# Get valid user data
100+
user = get_user_input()
101+
102+
# Count laptops for each operating system
103+
os_counts = {os_type: 0 for os_type in OperatingSystem}
104+
for laptop in laptops:
105+
os_counts[laptop.operating_system] += 1
106+
107+
# Look up counts for user choice and find the maximum available
108+
user_os = user.preferred_operating_system
109+
user_os_count = os_counts[user_os]
110+
111+
most_available_os = max(os_counts, key=os_counts.get)
112+
max_count = os_counts[most_available_os]
113+
114+
# Output results
115+
print(f"\nHello {user.name}!")
116+
print(f"The library has {user_os_count} laptop(s) running {user_os.value}.")
117+
118+
# Suggest alternative if another OS has more stock
119+
if max_count > user_os_count:
120+
print(
121+
f"💡 Tip: If you choose {most_available_os.value}, we have {max_count} laptops available. You're more likely to get one quickly!"
122+
)
123+
124+
125+
if __name__ == "__main__":
126+
main()

prep exercises/generics.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
from dataclasses import dataclass
2+
from typing import List
3+
4+
@dataclass(frozen=True)
5+
class Person:
6+
name: str
7+
age: int
8+
children: List["Person"]
9+
10+
fatma = Person(name="Fatma", age=10, children=[])
11+
aisha = Person(name="Aisha", age=15, children=[])
12+
13+
imran = Person(name="Imran", age=40, children=[fatma, aisha])
14+
15+
def print_family_tree(person: Person) -> None:
16+
print(person.name)
17+
for child in person.children:
18+
print(f"- {child.name} ({child.age})")
19+
20+
print_family_tree(imran)

prep exercises/inheritance.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
2+
3+
class Parent:
4+
def __init__(self, first_name: str, last_name: str):
5+
self.first_name = first_name
6+
self.last_name = last_name
7+
8+
def get_name(self) -> str:
9+
return f"{self.first_name} {self.last_name}"
10+
11+
12+
class Child(Parent):
13+
def __init__(self, first_name: str, last_name: str):
14+
super().__init__(first_name, last_name)
15+
self.previous_last_names = []
16+
17+
def change_last_name(self, last_name) -> None:
18+
self.previous_last_names.append(self.last_name)
19+
self.last_name = last_name
20+
21+
def get_full_name(self) -> str:
22+
suffix = ""
23+
if len(self.previous_last_names) > 0:
24+
suffix = f" (née {self.previous_last_names[0]})"
25+
return f"{self.first_name} {self.last_name}{suffix}"
26+
27+
28+
29+
person1 = Child("Elizaveta", "Alekseeva")
30+
# Predict: Creates a Child object. Works perfectly.
31+
32+
print(person1.get_name())
33+
# Predict: it will print "Elizaveta Alekseeva"
34+
# Child inherits this method from Parent
35+
36+
print(person1.get_full_name())
37+
# Predict: it will print "Elizaveta Alekseeva" because the last name has not been changed yet.
38+
# get_full_name is defined in Child, but it uses the last name from Parent, which is "Alekseeva" at this point.
39+
40+
person1.change_last_name("Tyurina")
41+
# Predict: Changes last_name to "Tyurina" and saves "Alekseeva" in the
42+
# previous_last_names list. Works perfectly.
43+
44+
print(person1.get_name())
45+
# Predict: Prints "Elizaveta Tyurina".
46+
# get_name is inherited from Parent, but it uses the updated last name "Tyurina".
47+
48+
print(person1.get_full_name())
49+
# Predict: Prints "Elizaveta Tyurina (née Alekseeva)".
50+
# get_full_name uses the updated last name "Tyurina" and also includes the previous last name "Alekseeva" in the output.
51+
print()
52+
53+
person2 = Parent("Elizaveta", "Alekseeva")
54+
# Predict: Creates a Parent object. Works perfectly.
55+
56+
print(person2.get_name())
57+
# Predict: it will print "Elizaveta Alekseeva"
58+
# get_name is defined in Parent, so it works perfectly.
59+
60+
print(person2.get_full_name())
61+
# Predict: it will raise an AttributeError because get_full_name is not defined in Parent,
62+
# and Parent does not have access to the methods of Child.
63+
64+
person2.change_last_name("Tyurina")
65+
# Predict: it will raise an AttributeError because change_last_name is not defined in Parent,
66+
# and Parent does not have access to the methods of Child.
67+
68+
print(person2.get_name())
69+
# Predict: it will print "Elizaveta Alekseeva" because the last name has not been changed due to the previous error.
70+
71+
print(person2.get_full_name())
72+
# Predict: it will raise an AttributeError again for the same reason as before.

prep exercises/methods.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
from datetime import date
2+
3+
4+
class Person:
5+
def __init__(self, name: str, date_of_birth: date, preferred_operating_system: str, favorite_sport: str) -> None:
6+
self.name = name
7+
self.date_of_birth = date_of_birth
8+
self.preferred_operating_system = preferred_operating_system
9+
self.favorite_sport = favorite_sport
10+
11+
def is_adult(self):
12+
today = date.today()
13+
age = today.year - self.date_of_birth.year
14+
15+
birthday_passed = (
16+
(today.month, today.day) >= (self.date_of_birth.month, self.date_of_birth.day)
17+
)
18+
if not birthday_passed:
19+
age -= 1
20+
return age >= 18
21+
22+
23+
24+
beko = Person("Beko", date(2005, 2, 17), "Linux", "Football")
25+
print(beko.is_adult())
26+
27+
28+
# Advantages of methods over free functions:
29+
30+
# Keep data and behavior together:
31+
# A method belongs directly to an object. It combines the object's info (data) and actions (behavior) into one package
32+
33+
# Make code easier to read:
34+
# You call them using object.action(). This reads like a normal sentence, making the code self-explanatory.
35+
# same (imran.is_adult() is easier to understand than is_adult(imran))
36+
37+
# Support inheritance:
38+
# Child objects automatically get access to the parent's methods. This means you do not have to copy and paste code.
39+
40+
# Enable polymorphism:
41+
# Different objects can use the exact same method name but handle it in their own unique way
42+
# (like a Dog and a Cat both responding to a .makeSound() method)

prep exercises/person_class.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
2+
3+
4+
class Person:
5+
def __init__(self, name: str, age: int, preferred_operating_system: str, favorite_sport: str) -> None:
6+
self.name = name
7+
self.age = age
8+
self.preferred_operating_system = preferred_operating_system
9+
self.favorite_sport = favorite_sport
10+
11+
def is_adult(self) -> bool:
12+
return self.age >= 18
13+
14+
def get_favorite_sport(self) -> str:
15+
return self.favorite_sport
16+
17+
18+
19+
imran = Person("Imran", 22, "Ubuntu", "Football")
20+
print(imran.name)
21+
print(imran.is_adult())
22+
print(imran.preferred_operating_system)
23+
print(imran.get_favorite_sport())
24+
25+
eliza = Person("Eliza", 34, "Arch Linux", "Tennis")
26+
print(eliza.name)
27+
print(eliza.is_adult())
28+
print(eliza.preferred_operating_system)
29+
print(eliza.get_favorite_sport())

0 commit comments

Comments
 (0)