Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
32 changes: 32 additions & 0 deletions prep exercises/checking_mypy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@


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: dict[str, int] = {
"Sima": 700,
"Linn": 545,
"Georg": 831,
}

open_account(balances, "Tobi", 913)
open_account(balances, "Olya", 713)

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

print(f"The bank accounts total {total_string}")
26 changes: 26 additions & 0 deletions prep exercises/dataclass.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@


from dataclasses import dataclass
from datetime import date

@dataclass(frozen=True)
class Person:
name: str
birth_day: date
preferred_OS: str


def is_adult(self):
today = date.today()
age = today.year - self.birth_day.year

if (today.month, today.day) < (self.birth_day.month, self.birth_day.day):
age -= 1
return age >= 18


beko = Person("Beko", date(2005, 2, 17), "Linux")
print(beko.is_adult())

noor = Person("Noor", date(2015, 2, 17), "Linux")
print(noor.is_adult())
18 changes: 18 additions & 0 deletions prep exercises/double.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@

def double (num):
return num * 2

print(double("22"))

# Predication
# Did it do what you expected?
# No, it didn't
#
# Why did it return the value it did?
# because there is a mistype in the function, it should take a number but the argument is string
#

def double_the_number(num):
return num * 3

print(double_the_number(5))
126 changes: 126 additions & 0 deletions prep exercises/enums.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
from dataclasses import dataclass
from enum import Enum
from typing import List
import sys


class OperatingSystem(Enum):
MACOS = "macOS"
ARCH = "Arch Linux"
UBUNTU = "Ubuntu"


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


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


# Existing inventory list
laptops = [
Laptop(
id=1,
manufacturer="Dell",
model="XPS",
screen_size_in_inches=13,
operating_system=OperatingSystem.ARCH,
),
Laptop(
id=2,
manufacturer="Dell",
model="XPS",
screen_size_in_inches=15,
operating_system=OperatingSystem.UBUNTU,
),
Laptop(
id=3,
manufacturer="Dell",
model="XPS",
screen_size_in_inches=15,
operating_system=OperatingSystem.UBUNTU,
),
Laptop(
id=4,
manufacturer="Apple",
model="macBook",
screen_size_in_inches=13,
operating_system=OperatingSystem.MACOS,
),
]


def get_user_input() -> Person:
name = input("Enter your name: ").strip()
if not name:
print("Error: Name cannot be empty.", file=sys.stderr)
sys.exit(1)

# 1. check the person's age is valid
try:
age = int(input("Enter your age: "))
if age < 0:
raise ValueError
except ValueError:
print("Error: Age must be a positive whole number.", file=sys.stderr)
sys.exit(1)

# 2. give the person a list of valid Operating Systems to choose from
print("\nAvailable Operating Systems:")
for os_option in OperatingSystem:
print(f"- {os_option.value}")

os_input = input("Enter your preferred operating system: ").strip()

# Try to match the user string to a valid Enum value
preferred_os = None
for os_option in OperatingSystem:
if os_option.value.lower() == os_input.lower():
preferred_os = os_option
break

if preferred_os is None:
print(f"Error: '{os_input}' is not a valid operating system.", file=sys.stderr)
sys.exit(1)

return Person(name=name, age=age, preferred_operating_system=preferred_os)


def main():
# Get valid user data
user = get_user_input()

# Count laptops for each operating system
os_counts = {os_type: 0 for os_type in OperatingSystem}
for laptop in laptops:
os_counts[laptop.operating_system] += 1

# Look up counts for user choice and find the maximum available
user_os = user.preferred_operating_system
user_os_count = os_counts[user_os]

most_available_os = max(os_counts, key=os_counts.get)
max_count = os_counts[most_available_os]

# Output results
print(f"\nHello {user.name}!")
print(f"The library has {user_os_count} laptop(s) running {user_os.value}.")

# Suggest alternative if another OS has more stock
if max_count > user_os_count:
print(
f"💡 Tip: If you choose {most_available_os.value}, we have {max_count} laptops available. You're more likely to get one quickly!"
)


if __name__ == "__main__":
main()
20 changes: 20 additions & 0 deletions prep exercises/generics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from dataclasses import dataclass
from typing import List

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

fatma = Person(name="Fatma", age=10, children=[])
aisha = Person(name="Aisha", age=15, children=[])

imran = Person(name="Imran", age=40, 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)
72 changes: 72 additions & 0 deletions prep exercises/inheritance.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@


class Parent:
def __init__(self, first_name: str, last_name: str):
self.first_name = first_name
self.last_name = last_name

def get_name(self) -> str:
return f"{self.first_name} {self.last_name}"


class Child(Parent):
def __init__(self, first_name: str, last_name: str):
super().__init__(first_name, last_name)
self.previous_last_names = []

def change_last_name(self, last_name) -> None:
self.previous_last_names.append(self.last_name)
self.last_name = last_name

def get_full_name(self) -> str:
suffix = ""
if len(self.previous_last_names) > 0:
suffix = f" (née {self.previous_last_names[0]})"
return f"{self.first_name} {self.last_name}{suffix}"



person1 = Child("Elizaveta", "Alekseeva")
# Predict: Creates a Child object. Works perfectly.

print(person1.get_name())
# Predict: it will print "Elizaveta Alekseeva"
# Child inherits this method from Parent

print(person1.get_full_name())
# Predict: it will print "Elizaveta Alekseeva" because the last name has not been changed yet.
# get_full_name is defined in Child, but it uses the last name from Parent, which is "Alekseeva" at this point.

person1.change_last_name("Tyurina")
# Predict: Changes last_name to "Tyurina" and saves "Alekseeva" in the
# previous_last_names list. Works perfectly.

print(person1.get_name())
# Predict: Prints "Elizaveta Tyurina".
# get_name is inherited from Parent, but it uses the updated last name "Tyurina".

print(person1.get_full_name())
# Predict: Prints "Elizaveta Tyurina (née Alekseeva)".
# get_full_name uses the updated last name "Tyurina" and also includes the previous last name "Alekseeva" in the output.
print()

person2 = Parent("Elizaveta", "Alekseeva")
# Predict: Creates a Parent object. Works perfectly.

print(person2.get_name())
# Predict: it will print "Elizaveta Alekseeva"
# get_name is defined in Parent, so it works perfectly.

print(person2.get_full_name())
# Predict: it will raise an AttributeError because get_full_name is not defined in Parent,
# and Parent does not have access to the methods of Child.

person2.change_last_name("Tyurina")
# Predict: it will raise an AttributeError because change_last_name is not defined in Parent,
# and Parent does not have access to the methods of Child.

print(person2.get_name())
# Predict: it will print "Elizaveta Alekseeva" because the last name has not been changed due to the previous error.

print(person2.get_full_name())
# Predict: it will raise an AttributeError again for the same reason as before.
42 changes: 42 additions & 0 deletions prep exercises/methods.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from datetime import date


class Person:
def __init__(self, name: str, date_of_birth: date, preferred_operating_system: str, favorite_sport: str) -> None:
self.name = name
self.date_of_birth = date_of_birth
self.preferred_operating_system = preferred_operating_system
self.favorite_sport = favorite_sport

def is_adult(self):
today = date.today()
age = today.year - self.date_of_birth.year

birthday_passed = (
(today.month, today.day) >= (self.date_of_birth.month, self.date_of_birth.day)
)
if not birthday_passed:
age -= 1
return age >= 18



beko = Person("Beko", date(2005, 2, 17), "Linux", "Football")
print(beko.is_adult())


# Advantages of methods over free functions:

# Keep data and behavior together:
# A method belongs directly to an object. It combines the object's info (data) and actions (behavior) into one package

# Make code easier to read:
# You call them using object.action(). This reads like a normal sentence, making the code self-explanatory.
# same (imran.is_adult() is easier to understand than is_adult(imran))

# Support inheritance:
# Child objects automatically get access to the parent's methods. This means you do not have to copy and paste code.

# Enable polymorphism:
# Different objects can use the exact same method name but handle it in their own unique way
# (like a Dog and a Cat both responding to a .makeSound() method)
29 changes: 29 additions & 0 deletions prep exercises/person_class.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@



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

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

def get_favorite_sport(self) -> str:
return self.favorite_sport



imran = Person("Imran", 22, "Ubuntu", "Football")
print(imran.name)
print(imran.is_adult())
print(imran.preferred_operating_system)
print(imran.get_favorite_sport())

eliza = Person("Eliza", 34, "Arch Linux", "Tennis")
print(eliza.name)
print(eliza.is_adult())
print(eliza.preferred_operating_system)
print(eliza.get_favorite_sport())
Loading
Loading