From c54ba92924ab5262854af30fd2a612db8a418d8c Mon Sep 17 00:00:00 2001 From: iswat Date: Sat, 11 Apr 2026 16:12:07 +0100 Subject: [PATCH 01/16] Update .gitignore to exclude Python and Java files - Add .venv to ignore Python virtual environments - Add *.class to ignore Java compiled class files --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 3c3629e64..be3563007 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ node_modules +.venv +*.class \ No newline at end of file From 1ae7aabeef4a1cdbd6688c26c676de1dbc67a0c0 Mon Sep 17 00:00:00 2001 From: iswat Date: Mon, 20 Apr 2026 20:24:30 +0100 Subject: [PATCH 02/16] Add why_we_use_types.py exercise with bug identification and fix - Add exercise demonstrating the importance of type hints - Include buggy double() function that multiplies by 3 instead of 2 - Document the bug and propose two possible fixes --- prep/why_we_use_types.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 prep/why_we_use_types.py diff --git a/prep/why_we_use_types.py b/prep/why_we_use_types.py new file mode 100644 index 000000000..afe0f27c1 --- /dev/null +++ b/prep/why_we_use_types.py @@ -0,0 +1,14 @@ +# Question + +def double(number): + return number * 3 + +print(double(10)) + +# Read the above code and write down what the bug is. How would you fix it? + + +# Answer +# The bug: The function multiplies the number by 3 instead of 2, which contradicts its name. + +# Proposed fix: We can either change the function implementation so that it returns number * 2 or we change the function name to 'triple' \ No newline at end of file From 2fc8ae2246f2c96e491513b7cfac8110685c230d Mon Sep 17 00:00:00 2001 From: iswat Date: Mon, 20 Apr 2026 20:27:01 +0100 Subject: [PATCH 03/16] Rename why_we_use_types.py to why_we_use_types_exercise2.py --- prep/{why_we_use_types.py => why_we_use_types_exercise2.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename prep/{why_we_use_types.py => why_we_use_types_exercise2.py} (100%) diff --git a/prep/why_we_use_types.py b/prep/why_we_use_types_exercise2.py similarity index 100% rename from prep/why_we_use_types.py rename to prep/why_we_use_types_exercise2.py From 1a7c06bf4214c70760f2061efd83e1697b294be4 Mon Sep 17 00:00:00 2001 From: iswat Date: Mon, 20 Apr 2026 21:36:27 +0100 Subject: [PATCH 04/16] Add why_we_use_types_exercise1.py with type behavior demonstration - Create exercise file demonstrating why type hints matter - Include half(), double(), and second() functions - Add example showing string multiplication vs numeric multiplication - Document expected behavior: double("22") returns "2222" due to string repetition - Include question and answer explaining the type-dependent behavior --- prep/why_we_use_types_exercise1.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 prep/why_we_use_types_exercise1.py diff --git a/prep/why_we_use_types_exercise1.py b/prep/why_we_use_types_exercise1.py new file mode 100644 index 000000000..ad2fabbe3 --- /dev/null +++ b/prep/why_we_use_types_exercise1.py @@ -0,0 +1,20 @@ +def half(value): + return value / 2 + +def double(value): + return value * 2 + +def second(value): + return value[1] + + +print(double("22")) + +# Question +# Predict what double("22") will do. Then run the code and check. Did it do what you expected? Why did it return the value it did? + +# Answer +# The function double("22") will return "2222". +# When I ran the program, it returned what I expected. +# The return value is "2222" because the argument is a string, so the * operator duplicates the string instead of +# multiplying a number. Python repeats the string twice: "22" + "22" = "2222". \ No newline at end of file From 1aca968ab82b6c9308fbaaac9d1ba0a29e2c0543 Mon Sep 17 00:00:00 2001 From: iswat Date: Mon, 20 Apr 2026 21:45:20 +0100 Subject: [PATCH 05/16] Fix type annotations and bugs in type_checking_with_mypy.py - Fix open_account() parameter: change 'balance' to 'balances' (NameError bug) - Add missing type annotations to all function parameters and return types - Run through mypy to validate all type hints are correct - Verify code runs without errors --- prep/type_checking_with_mypy.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 prep/type_checking_with_mypy.py diff --git a/prep/type_checking_with_mypy.py b/prep/type_checking_with_mypy.py new file mode 100644 index 000000000..d76222c19 --- /dev/null +++ b/prep/type_checking_with_mypy.py @@ -0,0 +1,30 @@ +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: int = sum_balances(balances) +total_string: str = format_pence_as_string(total_pence) + +print(f"The bank accounts total {total_string}") \ No newline at end of file From 6f0982b9bee80f945a3ade926e206ceb094b370e Mon Sep 17 00:00:00 2001 From: iswat Date: Wed, 22 Apr 2026 13:12:40 +0100 Subject: [PATCH 06/16] Add classes_and_objects_exercise1.py: demonstrate mypy type checking - Create Person class with type-annotated __init__ method - Add name (str), age (int), and preferred_operating_system (str) attributes - Create example instances (imran and eliza) - Intentionally access undefined 'address' attribute to demonstrate mypy error detection - Document the mypy error and explain the missing attribute issue --- prep/classes_and_objects_exercise1.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 prep/classes_and_objects_exercise1.py diff --git a/prep/classes_and_objects_exercise1.py b/prep/classes_and_objects_exercise1.py new file mode 100644 index 000000000..be344c64b --- /dev/null +++ b/prep/classes_and_objects_exercise1.py @@ -0,0 +1,17 @@ +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) + +# Answer +# The error returned after running mypy classes_and_objects_exercise1.py means that the Person class does not have an address attribute. +# An instance of Person was created with name, age and preferred_operating_system only. From 21fdd0ad512764353e8f9d895fd09c035ca03ba1 Mon Sep 17 00:00:00 2001 From: iswat Date: Wed, 22 Apr 2026 13:21:42 +0100 Subject: [PATCH 07/16] Add classes_and_objects_exercise2.py: demonstrate mypy type checking - Create Person class with type-annotated __init__ method - Add name (str), age (int), and preferred_operating_system (str) attributes - Implement is_adult() function that correctly accesses Person.age attribute - Add is_adult_wrong_attribute() function that intentionally accesses non-existent Person.address - Demonstrate mypy error detection for invalid attribute access - Show how mypy validates correct vs incorrect property references --- prep/classes_and_objects_exercise2.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 prep/classes_and_objects_exercise2.py diff --git a/prep/classes_and_objects_exercise2.py b/prep/classes_and_objects_exercise2.py new file mode 100644 index 000000000..a55b88563 --- /dev/null +++ b/prep/classes_and_objects_exercise2.py @@ -0,0 +1,22 @@ +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) + + +eliza = Person("Eliza", 34, "Arch Linux") +print(eliza.name) + +def is_adult(person: Person) -> bool: + return person.age >= 18 + +print(is_adult(imran)) + +def is_adult_wrong_attribute(person: Person) -> bool: + return person.address + +print(is_adult_wrong_attribute(imran)) \ No newline at end of file From 01fb96a1188d97c88cc505bf92f1d8bd5a8c64ca Mon Sep 17 00:00:00 2001 From: iswat Date: Wed, 22 Apr 2026 13:33:51 +0100 Subject: [PATCH 08/16] Add methods-exercise1.md: advantages of using methods vs free functions --- prep/methods-exercise1.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 prep/methods-exercise1.md diff --git a/prep/methods-exercise1.md b/prep/methods-exercise1.md new file mode 100644 index 000000000..34cc06ab0 --- /dev/null +++ b/prep/methods-exercise1.md @@ -0,0 +1,27 @@ +Here are the advantages of using methods instead of free functions: + +1. **Organization** - Methods are part of a class, so related code is organized together in one place. + +2. **Access to object data** - Methods can directly access the object's attributes (like `person.age`). Free functions need the object passed as a parameter. + +3. **Clearer intent** - When you see `person.is_adult()`, it's clear that you're asking "is this person an adult?" instead of `is_adult(person)`. + +4. **Less parameter passing** - Methods use `self` automatically, so you don't need to pass the object as a parameter every time. + +5. **Better grouping** - All actions for a `Person` are grouped together inside the `Person` class, not scattered around your code. + +6. **Easier to maintain** - If you need to change how `is_adult()` works, you only need to update the method in one place inside the class. + +7. **More readable** - `imran.is_adult()` is easier to read and understand than `is_adult(imran)`. + +**Example comparison:** + +```python +# Free function (current approach) +print(is_adult(imran)) + +# Method (better approach) +print(imran.is_adult()) +``` + +The method version is clearer and more organized! \ No newline at end of file From 4876f0d2c53a0be5331daa8b1a9ea9cb8f49dba9 Mon Sep 17 00:00:00 2001 From: iswat Date: Wed, 22 Apr 2026 13:39:26 +0100 Subject: [PATCH 09/16] Add methods-exercise2.py: refactor Person class to use date_of_birth - Replace age (int) parameter with date_of_birth (datetime.date) - Convert is_adult() from free function to instance method - Implement dynamic age calculation based on current date - Account for whether birthday has occurred this year - Add type hints for all parameters and return types - Include example usage with imran and eliza instances --- prep/methods-exercise2.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 prep/methods-exercise2.py diff --git a/prep/methods-exercise2.py b/prep/methods-exercise2.py new file mode 100644 index 000000000..d5ed52ea3 --- /dev/null +++ b/prep/methods-exercise2.py @@ -0,0 +1,25 @@ +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) -> bool: + today = date.today() + age = today.year - self.date_of_birth.year + + # Check if birthday has occurred this 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(2002, 5, 15), "Ubuntu") +print(imran.name) +print(imran.is_adult()) + +eliza = Person("Eliza", date(1990, 3, 20), "Arch Linux") +print(eliza.name) +print(eliza.is_adult()) \ No newline at end of file From ffc50f6470b4128e1fd954d7a9ca79a0a80fae19 Mon Sep 17 00:00:00 2001 From: iswat Date: Wed, 22 Apr 2026 13:42:41 +0100 Subject: [PATCH 10/16] Add dataclasses-exercise.py: Person class using @dataclass decorator - Create Person class with @dataclass(frozen=True) decorator - Use datetime.date for date_of_birth instead of int for age - Replace manual __init__ with declarative field definitions - Implement is_adult() method with dynamic age calculation - Account for whether birthday has occurred this year - Add type hints for all attributes and methods - Include example usage with imran and eliza instances - Demonstrate immutable dataclass with frozen=True --- prep/dataclasses-exercise.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 prep/dataclasses-exercise.py diff --git a/prep/dataclasses-exercise.py b/prep/dataclasses-exercise.py new file mode 100644 index 000000000..8ea701586 --- /dev/null +++ b/prep/dataclasses-exercise.py @@ -0,0 +1,26 @@ +from datetime import date +from dataclasses import dataclass + +@dataclass(frozen=True) +class Person: + name: str + date_of_birth: date + preferred_operating_system: str + + def is_adult(self) -> bool: + today = date.today() + age = today.year - self.date_of_birth.year + + # Check if birthday has occurred this 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(2002, 5, 15), "Ubuntu") +print(imran.name) +print(imran.is_adult()) + +eliza = Person("Eliza", date(1990, 3, 20), "Arch Linux") +print(eliza.name) +print(eliza.is_adult()) \ No newline at end of file From d1882e630004e096c9f03af04492729b1a65ebd8 Mon Sep 17 00:00:00 2001 From: iswat Date: Wed, 22 Apr 2026 15:09:42 +0100 Subject: [PATCH 11/16] Add generics-exercise1.py: demonstrate generic types with Person class - Create Person dataclass with @dataclass(frozen=True) decorator - Use List["Person"] generic type for children attribute (self-referencing) - Implement age() method that calculates age from date_of_birth - Add example Person instances: fatma, aisha, and imran - Implement print_family_tree() function to display family hierarchy - Demonstrate practical use of generics for type-safe collections - Show how mypy validates generic type parameters --- prep/generics-exercise1.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 prep/generics-exercise1.py diff --git a/prep/generics-exercise1.py b/prep/generics-exercise1.py new file mode 100644 index 000000000..e64be2717 --- /dev/null +++ b/prep/generics-exercise1.py @@ -0,0 +1,30 @@ +from dataclasses import dataclass +from typing import List +from datetime import date + +@dataclass(frozen=True) +class Person: + name: str + date_of_birth: date + children: List["Person"] + + def age(self) -> int: + 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 + +fatma = Person(name="Fatma", date_of_birth=date(2015, 7, 22), children=[]) +aisha = Person(name="Aisha", date_of_birth=date(2018, 3, 10), children=[]) + +imran = Person(name="Imran", date_of_birth=date(1985, 5, 15), 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) + + From 3c7f26aabe847a1b6a33d7496b096b26eb8d3ad7 Mon Sep 17 00:00:00 2001 From: iswat Date: Wed, 22 Apr 2026 15:58:40 +0100 Subject: [PATCH 12/16] Add type-guided-refactoring-exercise.py: refactor using generic List types - Change Person.preferred_operating_system from str to List[str] - Rename field to preferred_operating_systems (plural) - Update find_possible_laptops() to check if OS is in list using 'in' operator - Add example Person instances with multiple preferred operating systems - Add sample Laptop instances for testing - Demonstrate practical use of generic List types with dataclasses - Run through mypy to validate all type annotations are correct --- prep/type-guided-refactoring-exercise.py | 42 ++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 prep/type-guided-refactoring-exercise.py diff --git a/prep/type-guided-refactoring-exercise.py b/prep/type-guided-refactoring-exercise.py new file mode 100644 index 000000000..104c3dea2 --- /dev/null +++ b/prep/type-guided-refactoring-exercise.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 From 535683fa101f3e49ee40015849c1258adad82868 Mon Sep 17 00:00:00 2001 From: iswat Date: Wed, 22 Apr 2026 16:12:10 +0100 Subject: [PATCH 13/16] Add enums-exercise.py: library laptop matching system with type-safe enums - Create OperatingSystem Enum with MACOS, ARCH, and UBUNTU values - Define Person dataclass with preferred_operating_system as Enum type - Define Laptop dataclass with operating_system as Enum type - Implement find_possible_laptops() function to match laptops to person preferences - Add library inventory: 4 sample laptops with different operating systems - Add sample people with OS preferences - Demonstrate type-safe enum usage vs string-based approach - Display matching laptops for each person --- prep/enums-exercise.py | 48 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 prep/enums-exercise.py diff --git a/prep/enums-exercise.py b/prep/enums-exercise.py new file mode 100644 index 000000000..e33930ac6 --- /dev/null +++ b/prep/enums-exercise.py @@ -0,0 +1,48 @@ +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 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}") \ No newline at end of file From 67c5dff3eec0f3521bffb1cfbdf5d1a919e13f2a Mon Sep 17 00:00:00 2001 From: iswat Date: Wed, 22 Apr 2026 19:35:45 +0100 Subject: [PATCH 14/16] Add interactive user input to enums-exercise.py - Add create_person_from_input() function for interactive person creation - Prompt user for name, age, and preferred operating system - Display available OS options from OperatingSystem Enum - Validate user input with try/except for invalid OS choices - Create Person instance and find matching laptops - Display matching laptops for newly created person - Maintain existing hardcoded people and laptop matching - Add interactive section at end to test user input functionality --- prep/enums-exercise.py | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/prep/enums-exercise.py b/prep/enums-exercise.py index e33930ac6..2283711d0 100644 --- a/prep/enums-exercise.py +++ b/prep/enums-exercise.py @@ -31,10 +31,26 @@ def find_possible_laptops(laptops: List[Laptop], person: Person) -> List[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), -] +def create_person_from_input(laptops: List[Laptop]) -> None: + name = input("Enter person's name: ") + age = int(input("Enter person's age: ")) + + print("Available operating systems:") + for os in OperatingSystem: + print(f" {os.name}: {os.value}") + + os_choice = input("Enter preferred operating system (MACOS/ARCH/UBUNTU): ").upper() + + try: + preferred_os = OperatingSystem[os_choice] + except KeyError: + print("Invalid operating system choice!") + return + + person = Person(name=name, age=age, preferred_operating_system=preferred_os) + possible_laptops = find_possible_laptops(laptops, person) + print(f"Possible laptops for {person.name}: {possible_laptops}") + laptops = [ Laptop(id=1, manufacturer="Dell", model="XPS", screen_size_in_inches=13, operating_system=OperatingSystem.ARCH), @@ -43,6 +59,14 @@ def find_possible_laptops(laptops: List[Laptop], person: Person) -> List[Laptop] Laptop(id=4, manufacturer="Apple", model="macBook", screen_size_in_inches=13, operating_system=OperatingSystem.MACOS), ] +people = [ + Person(name="Imran", age=22, preferred_operating_system=OperatingSystem.UBUNTU), + Person(name="Eliza", age=34, preferred_operating_system=OperatingSystem.ARCH), +] + 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 + print(f"Possible laptops for {person.name}: {possible_laptops}") + +print("\n--- Create a new person ---") +create_person_from_input(laptops) \ No newline at end of file From 0f884bd1b02fd030a92be32909a0554abfb51e60 Mon Sep 17 00:00:00 2001 From: iswat Date: Wed, 22 Apr 2026 19:42:34 +0100 Subject: [PATCH 15/16] Improve enums-exercise.py: enhance output messaging and formatting - Add newline before possible laptops output for better readability - Add summary message showing count of available laptops - Display the operating system name using enum.value property - Improve user feedback with clearer output format --- prep/enums-exercise.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/prep/enums-exercise.py b/prep/enums-exercise.py index 2283711d0..a0b962b4c 100644 --- a/prep/enums-exercise.py +++ b/prep/enums-exercise.py @@ -49,8 +49,9 @@ def create_person_from_input(laptops: List[Laptop]) -> None: person = Person(name=name, age=age, preferred_operating_system=preferred_os) possible_laptops = find_possible_laptops(laptops, person) - print(f"Possible laptops for {person.name}: {possible_laptops}") - + + print(f"\nPossible laptops for {person.name}: {possible_laptops}") + print(f"The library has {len(possible_laptops)} laptop(s) with {preferred_os.value}") laptops = [ Laptop(id=1, manufacturer="Dell", model="XPS", screen_size_in_inches=13, operating_system=OperatingSystem.ARCH), From 120cd4fc5cca1a333590131d28ef2a09857ad0c7 Mon Sep 17 00:00:00 2001 From: iswat Date: Wed, 22 Apr 2026 22:55:04 +0100 Subject: [PATCH 16/16] That's why those lines errored - you were trying to use Child-only methods on a Parent object! --- prep/inheritance-exercise.py | 37 ++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 prep/inheritance-exercise.py diff --git a/prep/inheritance-exercise.py b/prep/inheritance-exercise.py new file mode 100644 index 000000000..215cf36d2 --- /dev/null +++ b/prep/inheritance-exercise.py @@ -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()) +#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()) \ No newline at end of file