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
24 changes: 24 additions & 0 deletions prep exercises/Classes and objects exercise 1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
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) # error: "Person" has no attribute "address" [attr-defined]

eliza = Person("Eliza", 34, "Arch Linux")
print(eliza.name)
# print(eliza.address) # error: "Person" has no attribute "address" [attr-defined]

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

print(is_adult(imran))

def no_attribute_exists(person: Person):
print(person.dob)

# mypy detects that dob attribute doesn't exist.
# error: "Person" has no attribute "dob" [attr-defined]
23 changes: 23 additions & 0 deletions prep exercises/Dataclasses exercise.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from dataclasses import dataclass
from datetime import date

@dataclass(frozen=True)
class Person:
name: str
date_of_birth: date
preferred_operating_system: str

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

if (today.month, today.day) < (self.date_of_birth.month, self.date_of_birth.day):
age -= 1

return age >= 18

imran = Person("Imran", date(2004, 6, 28), "Ubuntu") # We can call this constructor - @dataclass generated it for us.
print(imran) # Prints Person(name='Imran', age=22, preferred_operating_system='Ubuntu')

imran2 = Person("Imran", date(2004, 6, 28), "Ubuntu")
print(imran == imran2) # Prints True
109 changes: 109 additions & 0 deletions prep exercises/Enums exercise.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
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


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


people = [
Person(name="Imran", age=22, preferred_operating_system=OperatingSystem.UBUNTU),
Person(name="Eliza", age=34, preferred_operating_system=OperatingSystem.ARCH),
]

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),
]

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

name = input("Please enter your name: ")

def get_age() -> int:
while True:
try:
age_string = input("Please enter your age, you must be >= 18 years old: ")
age = int(age_string)

if age < 18:
print("You must be 18+.")
continue

return age
except ValueError:
print("Please enter a valid number.")

age = get_age()

def get_preferred_operating_system() -> OperatingSystem:
while True:
preferred_operating_system_input = input("Your preferred operating system (macOS, Ubuntu or Arch Linux): ")

try:
normalised_value = preferred_operating_system_input.strip()
operating_system = OperatingSystem(normalised_value)
return operating_system
except ValueError:
print(f"Sorry, we don't have {preferred_operating_system_input}. Please choose from macOS, Ubuntu or Arch Linux.")

operating_system = get_preferred_operating_system()

person = Person(name=name, age=age, preferred_operating_system=operating_system)
people.append(person)

def find_laptop() -> None:
matching_laptops = []
non_matching_laptops = []

for laptop in laptops:
if laptop.operating_system == person.preferred_operating_system:
matching_laptops.append(laptop)
else:
non_matching_laptops.append(laptop)

if matching_laptops:
count = len(matching_laptops)
print(f"Congratulations, we have found {count} matching laptops!")

other_laptops_count = len(non_matching_laptops)

if other_laptops_count > count:
print(f"We have found {other_laptops_count} laptops with other operating systems. You might be interested in switching to a different operating system.")

sys.exit(0)
else:
sys.exit("Sorry, we couldn't find any matching laptops!")


find_laptop()
20 changes: 20 additions & 0 deletions prep exercises/Generics exercise.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=7, children=[])
aisha = Person(name="Aisha", age=11, children=[])

imran = Person(name="Imran", age=32, 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)
37 changes: 37 additions & 0 deletions prep exercises/Inheritance.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
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")
print(person1.get_name()) # Should print Elizaveta Actual: Elizaveta Alekseeva
print(person1.get_full_name()) # Should print Elizaveta Alekseeva
person1.change_last_name("Tyurina")
print(person1.get_name()) # Should print Elizaveta Actual: Elizaveta Tyurina
print(person1.get_full_name()) # Should print Elizaveta Alekseeva (née Tyurina) Actual: Elizaveta Tyurina (née Alekseeva)

person2 = Parent("Elizaveta", "Alekseeva")
print(person2.get_name()) # Should print Elizaveta Alekseeva
# print(person2.get_full_name()) # Method doesn't exist because only Child class has it.
# person2.change_last_name("Tyurina") # Method doesn't exist because only Child class has it.
print(person2.get_name()) # Should print Elizaveta Alekseeva
# print(person2.get_full_name()) # Method doesn't exist because only Child class has it.
4 changes: 4 additions & 0 deletions prep exercises/Methods exercise 1
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
The advantage of a method as a opposed to freestanding function is that it works on the instance of a type.
The freestanding function knows nothing about the instance of the type because it doesn't belong to a type.
On an instance, the method can influence the internal states.
However freestanding function can only work on public APIs whereas instance methods have access to internal APIs.
19 changes: 19 additions & 0 deletions prep exercises/Methods exercise 2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from datetime import date

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

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

if (today.month, today.day) < (self.date_of_birth.month, self.date_of_birth.day):
age -= 1

return age >= 18

imran = Person("Imran", date(2004, 6, 28), "Ubuntu")
print(imran.is_adult())
34 changes: 34 additions & 0 deletions prep exercises/Type checking with mypy exercise.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
def open_account(balances: dict[str, float], name: str, amount: float) -> None:
balances[name] = amount

def sum_balances(accounts: dict[str, float]) -> float:
total: float = 0

for name, pence in accounts.items():
print(f"{name} had balance {pence}")
total += pence

return total

def format_pence_as_string(total_pence: float) -> str:
if total_pence < 100:
return f"{total_pence}p"

pounds = int(total_pence / 100)
pence = int(total_pence % 100)

return f"£{pounds}.{pence:02d}"

balances: dict[str, float] = {
"Sima": 700,
"Linn": 545,
"Georg": 831,
}

open_account(balances, "Tobi", 9.13)
open_account(balances, "Olya", 7.13)

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

print(f"The bank accounts total {total_string}")
42 changes: 42 additions & 0 deletions prep exercises/Type-guided refactorings exercise.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
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:
if laptop.operating_system in person.preferred_operating_systems:
possible_laptops.append(laptop)
return possible_laptops


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

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}")
9 changes: 9 additions & 0 deletions prep exercises/Why we use types exercise 1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
def double(value):
return value * 2

# I predict that double("22") will produce 22.0

result = double("22")
print(result) # Actual result is 2222

# This is because the string is duplicated twice, "22" + "22" = "22" * 2, it is repeating the a sequence of string.
15 changes: 15 additions & 0 deletions prep exercises/Why we use types exercise 2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
def double(number):
return number * 3

print(double(10))

# There are two possible ways to fix the bug.

# 1. The function name is wrong, it needs to be named to triple
# 2. Or the function name is correct but the calculation is wrong, it should be return * 2

def double(number):
return number * 2

value = 10
print(double(value))
Loading