From e2173054f45572e145170a2cb7a19f986682027c Mon Sep 17 00:00:00 2001 From: Xinxi Date: Sat, 2 May 2026 19:22:54 +0200 Subject: [PATCH 1/2] dataclass.py --- Sprint5/Limits of type checking.py | 5 ++++ Sprint5/class&objects.py | 13 ++++++++++ Sprint5/dataclass.py | 26 +++++++++++++++++++ Sprint5/methods.py | 24 ++++++++++++++++++ Sprint5/mypy.py | 40 ++++++++++++++++++++++++++++++ 5 files changed, 108 insertions(+) create mode 100644 Sprint5/Limits of type checking.py create mode 100644 Sprint5/class&objects.py create mode 100644 Sprint5/dataclass.py create mode 100644 Sprint5/methods.py create mode 100644 Sprint5/mypy.py diff --git a/Sprint5/Limits of type checking.py b/Sprint5/Limits of type checking.py new file mode 100644 index 000000000..18ed2364c --- /dev/null +++ b/Sprint5/Limits of type checking.py @@ -0,0 +1,5 @@ +def double(number): + return number * 3 +print(double(10)) + +#this code runs perfectly. \ No newline at end of file diff --git a/Sprint5/class&objects.py b/Sprint5/class&objects.py new file mode 100644 index 000000000..6d333ffd7 --- /dev/null +++ b/Sprint5/class&objects.py @@ -0,0 +1,13 @@ +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) \ No newline at end of file diff --git a/Sprint5/dataclass.py b/Sprint5/dataclass.py new file mode 100644 index 000000000..7367a664b --- /dev/null +++ b/Sprint5/dataclass.py @@ -0,0 +1,26 @@ +from dataclasses import dataclass +from datetime import date + +@dataclass(frozen=True) +class Person: + name: str + birth_date: date + preferred_operating_system: str + + def is_adult(self) -> bool: + today = date.today() + age = today.year - self.birth_date.year + + birthday_has_passed = (today.month, today.day) >= (self.birth_date.month, self.birth_date.day) + + if not birthday_has_passed: + age -= 1 + + return age >= 18 + +imran1 = Person("Imran", date(2000, 5, 20), "Ubuntu") +imran2 = Person("Imran", date(2000, 5, 20), "Ubuntu") + +print(imran1) +print(f"Are they equal? {imran1 == imran2}") +print(f"Is Imran an adult? {imran1.is_adult()}") \ No newline at end of file diff --git a/Sprint5/methods.py b/Sprint5/methods.py new file mode 100644 index 000000000..71760d4f0 --- /dev/null +++ b/Sprint5/methods.py @@ -0,0 +1,24 @@ +# The advantage of using methods instead of free functions. +# 1. Encapsulation & Organization: methods group behavior directly with the data it operates on the object. +# 2. State management: methods have direct access to 'self'. +# 3. Readibility. + +from datetime import date + +class Person: + def __init__(self, name: str, birth_date: date, preferred_operating_system: str): + self.name = name + self.birth_date = birth_date + self.preferred_operating_system = preferred_operating_system + + def is_adult(self) -> bool: + today = date.today() + age = today.year - self.birth_date.year + birthday_has_passed: bool = (today.month, today.day) >= (self.birth_date.month, self.birth_date.day) + + if not birthday_has_passed: + age -= 1 + return age >= 18 + +imran = Person("Imran", date(2000, 5, 20), "Ubuntu") +print(f"Is Imran an adult? {imran.is_adult()}") \ No newline at end of file diff --git a/Sprint5/mypy.py b/Sprint5/mypy.py new file mode 100644 index 000000000..eedb8c01b --- /dev/null +++ b/Sprint5/mypy.py @@ -0,0 +1,40 @@ +from typing import Dict + +# Added Type Annotations +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}") + # If 'pence' isn't an int, this will fail or cause issues later + total += pence + return total + +def format_pence_as_string(total_pence: int) -> str: + if total_pence < 100: + return f"{total_pence}p" + # Use // for floor division to ensure 'pounds' is an int + pounds = total_pence // 100 + pence = total_pence % 100 + return f"£{pounds}.{pence:02d}" + +balances: Dict[str, int] = { + "Sima": 700, + "Linn": 545, + "Georg": 831, +} + +# BUGS FIXED HERE: +# Changed 9.13 (float) to 913 (int) +# Changed "£7.13" (str) to 713 (int) +open_account(balances, "Tobi", 913) +open_account(balances, "Olya", 713) + +total_pence = sum_balances(balances) + +# BUG FIXED HERE: Corrected the function name call +total_string = format_pence_as_string(total_pence) + +print(f"The bank accounts total {total_string}") \ No newline at end of file From e6858b585ce50e7f10704b1a4c5e2ad3fb5ac5a0 Mon Sep 17 00:00:00 2001 From: Xinxi Date: Sun, 3 May 2026 22:10:51 +0200 Subject: [PATCH 2/2] inheritance.py --- Sprint5/enums.py | 65 +++++++++++++++++++++++++++++ Sprint5/generics.py | 23 ++++++++++ Sprint5/inheritance.py | 40 ++++++++++++++++++ Sprint5/type-guided refactorings.py | 42 +++++++++++++++++++ 4 files changed, 170 insertions(+) create mode 100644 Sprint5/enums.py create mode 100644 Sprint5/generics.py create mode 100644 Sprint5/inheritance.py create mode 100644 Sprint5/type-guided refactorings.py diff --git a/Sprint5/enums.py b/Sprint5/enums.py new file mode 100644 index 000000000..206aae83f --- /dev/null +++ b/Sprint5/enums.py @@ -0,0 +1,65 @@ +import sys +from dataclasses import dataclass +from enum import Enum +from typing import List + +class OperatingSystem(Enum): + MACOS = "macOS" + ARCH = "Arch Linux" + UBUNTU = "Ubuntu" + +@dataclass(frozen=True) +class Laptop: + id: int + operating_system: OperatingSystem + +@dataclass(frozen=True) +class Person: + name: str + age: int + preferred_operating_system: OperatingSystem + +laptops = [ + Laptop(id=1, operating_system=OperatingSystem.ARCH), + Laptop(id=2, operating_system=OperatingSystem.UBUNTU), + Laptop(id=3, operating_system=OperatingSystem.UBUNTU), + Laptop(id=4, operating_system=OperatingSystem.MACOS), + Laptop(id=5, operating_system=OperatingSystem.UBUNTU), +] + +def get_user_person() -> Person: + name = input("Enter your name: ") + + try: + age = int(input("Enter your age: ")) + except ValueError: + print("Error: Age must be a number.", file=sys.stderr) + sys.exit(1) + + os_input = input("Enter preferred OS (macOS, Arch Linux, Ubuntu): ") + try: + pref_os = OperatingSystem(os_input) + except ValueError: + 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=pref_os) + +def main(): + user = get_user_person() + counts = {os: 0 for os in OperatingSystem} + for laptop in laptops: + counts[laptop.operating_system] += 1 + + user_pref = user.preferred_operating_system + pref_count = counts[user_pref] + print(f"There are {pref_count} laptops available with {user_pref.value}.") + + best_os = max(counts, key=counts.get) + max_count = counts[best_os] + + if max_count > pref_count: + print(f"Note: If you are willing to use {best_os.value}, we have {max_count} available. " + "You're more likely to get one!") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/Sprint5/generics.py b/Sprint5/generics.py new file mode 100644 index 000000000..9ad0071b1 --- /dev/null +++ b/Sprint5/generics.py @@ -0,0 +1,23 @@ +from dataclasses import dataclass +from typing import List + +@dataclass(frozen=True) +class Person: + name: str + age: int # Added the missing field + children: List["Person"] + +# Inventing ages for the family members +fatma = Person(name="Fatma", age=8, children=[]) +aisha = Person(name="Aisha", age=10, children=[]) + +# Imran needs an age as well, and now includes his 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: + # This line now works because 'age' exists in the Person class + print(f"- {child.name} ({child.age})") + +print_family_tree(imran) \ No newline at end of file diff --git a/Sprint5/inheritance.py b/Sprint5/inheritance.py new file mode 100644 index 000000000..111002969 --- /dev/null +++ b/Sprint5/inheritance.py @@ -0,0 +1,40 @@ +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()) +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()) + +# The Child can access everything the Parent has because it inherits from it. +# The parent has no attribute of the Child. \ No newline at end of file diff --git a/Sprint5/type-guided refactorings.py b/Sprint5/type-guided refactorings.py new file mode 100644 index 000000000..104c3dea2 --- /dev/null +++ b/Sprint5/type-guided refactorings.py @@ -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", "Arch Linux"]), + 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}") \ No newline at end of file