diff --git a/.gitignore b/.gitignore index 3c3629e64..3e5cc695e 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ node_modules +.venv/ \ No newline at end of file diff --git a/prep-exercises/__pycache__/dataclasses.cpython-312.pyc b/prep-exercises/__pycache__/dataclasses.cpython-312.pyc new file mode 100644 index 000000000..3733526e3 Binary files /dev/null and b/prep-exercises/__pycache__/dataclasses.cpython-312.pyc differ diff --git a/prep-exercises/classes_and_objects.py b/prep-exercises/classes_and_objects.py new file mode 100644 index 000000000..cc862f7f1 --- /dev/null +++ b/prep-exercises/classes_and_objects.py @@ -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 + + +def is_adult(person: Person) -> bool: + return person.age >= 18 + + +imran = Person("Imran", 22, "Ubuntu") +print(imran.name) +# print(imran.address) +# Person doesn't have address attribute + +eliza = Person("Eliza", 34, "Arch Linux") +print(eliza.name) +# print(eliza.address) +# Person doesn't have address attribute + +# def favorite_song(person: Person) -> str: +# return person.song +# error because person doesn't have song attribute diff --git a/prep-exercises/dataclasses_exercise.py b/prep-exercises/dataclasses_exercise.py new file mode 100644 index 000000000..6b6722122 --- /dev/null +++ b/prep-exercises/dataclasses_exercise.py @@ -0,0 +1,25 @@ +from dataclasses import dataclass +import datetime as dt + +@dataclass(frozen=True) +class Person: + name: str + age: dt.date + preferred_operating_system: str + + def is_adult(self) -> bool: + today = dt.datetime.today() + + age_in_year = today.year - self.age.year + + if (today.month, today.day) < (self.age.month, self.age.day): + age_in_year -= 1 + return age_in_year >= 18 + +imran = Person("Imran", dt.date.fromisoformat("2002-08-05"), "Ubuntu") +print(imran) + +imran2 = Person("Imran", dt.date.fromisoformat("2002-08-05"), "Ubuntu") +print(imran == imran2) + +print(f'{imran.name} is adult: {imran.is_adult()}') diff --git a/prep-exercises/enums.py b/prep-exercises/enums.py new file mode 100644 index 000000000..0d7edb570 --- /dev/null +++ b/prep-exercises/enums.py @@ -0,0 +1,80 @@ +from dataclasses import dataclass +from enum import Enum +from typing import List, Dict +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 + +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 user_register() -> Person: + + user_name: str = input("Please enter your name: ") + user_age_str: str = input("Please enter your age: ") + + try: + user_age: int = int(user_age_str) + if user_age < 0: + raise ValueError + except ValueError: + sys.stderr.write(f'Error: "{user_age_str}" is not a valid age. \n') + sys.exit(1) + + user_system_str = input("Please enter your preferred operating system - Arch Linux, Ubuntu, or macOS: ") + + try: + user_system = OperatingSystem(user_system_str) + except ValueError: + sys.stderr.write(f'Error: "{user_system_str}" is not a valid system. \n') + sys.exit(1) + + return Person(name=user_name, age=user_age, preferred_operating_system=user_system) + + +def matching_laptop(new_user: Person = user_register()) -> None: + possible_laptops = find_possible_laptops(laptops=laptops, person=new_user) + + print(f'Library has {len(possible_laptops)} laptops have {new_user.preferred_operating_system.value}') + + system_counts: Dict[OperatingSystem, int] = {} + for laptop in laptops: + system_counts[laptop.operating_system] = (system_counts.get(laptop.operating_system) or 0 ) + 1 + + most_available = max(system_counts, key=lambda name: system_counts[name]) + + if system_counts[most_available] > len(possible_laptops): + print(f'if you are willing to accept {most_available.value} you are more likely to get a laptop.') + + +matching_laptop() diff --git a/prep-exercises/generics.py b/prep-exercises/generics.py new file mode 100644 index 000000000..1b2fcd656 --- /dev/null +++ b/prep-exercises/generics.py @@ -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=12, children=[]) + +imran = Person(name="Imran", age=50, 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) diff --git a/prep-exercises/inheritance.py b/prep-exercises/inheritance.py new file mode 100644 index 000000000..d9fdccdd6 --- /dev/null +++ b/prep-exercises/inheritance.py @@ -0,0 +1,50 @@ +from typing import List + +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: List[str] = [] + + def change_last_name(self, last_name: str) -> 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()) +print(person1.get_full_name()) +person1.change_last_name("Tyurina") +print(person1.get_name()) +print(person1.get_full_name()) + +person2 = Parent("Elizaveta", "Alekseeva") +print(person2.get_name()) +# print(person2.get_full_name()) +# person2.change_last_name("Tyurina") +print(person2.get_name()) +# print(person2.get_full_name()) + + +# Predictions: +# person 1 should be able to print both name and full name as Elizaveta Alekseeva +# and should be able to print both name Elizaveta Tyurina and full name Elizaveta Tyurina (née Alekseeva) after changing last name to Tyurina +# because it was created in class Child which inherits get_name from class Parent +# +# In contracts, person 2 is able to print name as Elizaveta Alekseeva +# but shouldn't be able to print full name as it was create in class Parent, which does not have method get_full_name +# and couldn't be able to change last name to Tyurina, so the name stays the same Elizaveta Alekseeva +# and it still won't be able to print full name even after the attempt of change last name diff --git a/prep-exercises/methods.py b/prep-exercises/methods.py new file mode 100644 index 000000000..414e2c2fe --- /dev/null +++ b/prep-exercises/methods.py @@ -0,0 +1,23 @@ +# Think of the advantages of using methods instead of free functions. Write them down in your notebook. +# It is object oriented. The same method can be shared between the same class. +# It is more obvious to understand the purpose of the methods than a free function + +import datetime as dt + +class Person: + def __init__(self, name: str, date_of_birth: str, preferred_operating_system: str): + self.name = name + self.date_of_birth = dt.date.fromisoformat(date_of_birth) + self.preferred_operating_system = preferred_operating_system + + def is_adult(self) -> bool: + today = dt.datetime.today() + + age_in_year = today.year - self.date_of_birth.year + + if (today.month, today.day) < (self.date_of_birth.month, self.date_of_birth.day): + age_in_year -= 1 + return age_in_year >= 18 + +imran = Person("Imran", "2000-10-20", "Ubuntu") +print(imran.is_adult()) diff --git a/prep-exercises/type_checking_with_mypy.py b/prep-exercises/type_checking_with_mypy.py new file mode 100644 index 000000000..c1f5af71b --- /dev/null +++ b/prep-exercises/type_checking_with_mypy.py @@ -0,0 +1,32 @@ +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", 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}") diff --git a/prep-exercises/type_guided_refactorings.py b/prep-exercises/type_guided_refactorings.py new file mode 100644 index 000000000..306a477d8 --- /dev/null +++ b/prep-exercises/type_guided_refactorings.py @@ -0,0 +1,57 @@ +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 system in person.preferred_operating_systems: + if laptop.operating_system == system: + possible_laptops.append(laptop) + return possible_laptops + + +people = [ + Person(name="Imran", age=22, preferred_operating_systems=["Ubuntu", "Arch Linux", "macOS", "Windows"]), + Person(name="Eliza", age=34, preferred_operating_systems=["Arch Linux", "Ubuntu", "macOS", "Windows"]), +] + +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}") + + system_list = person.preferred_operating_systems + preference_sentences: List[str] = ["prefers {} most of all", ", and then {}", ", but will not use {}"] + statement: str = f'{person.name} ' + + if len(system_list) != 0: + for index, system in enumerate(system_list): + if index == 0: + statement += preference_sentences[index].format(system) + elif index == len(system_list) - 1: + statement += preference_sentences[-1].format(system) + else: + statement += preference_sentences[1].format(system) + print(statement) diff --git a/prep-exercises/why_we_use_types.py b/prep-exercises/why_we_use_types.py new file mode 100644 index 000000000..95fc497fb --- /dev/null +++ b/prep-exercises/why_we_use_types.py @@ -0,0 +1,9 @@ +def double(number: float) -> float: + return number * 2 + +print(double(10)) + +# The code above was not defined with types for the function and variable +# I should add the types to fix the code +# Besides the function name did not reflect its return +# I make the return as number * 2 instead