From 4a2895919564b1a4b0cc6e42dac362c712dfb202 Mon Sep 17 00:00:00 2001 From: shreefAhmedM Date: Sun, 9 Aug 2026 12:30:51 +0100 Subject: [PATCH 01/13] producting what 2 * 22 will do in py --- sprint5-prep-exercises/predictDouble.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 sprint5-prep-exercises/predictDouble.py diff --git a/sprint5-prep-exercises/predictDouble.py b/sprint5-prep-exercises/predictDouble.py new file mode 100644 index 000000000..866197dd1 --- /dev/null +++ b/sprint5-prep-exercises/predictDouble.py @@ -0,0 +1,13 @@ +def half(value): + return value / 2 + +def double(value): + return value * 2 + +def second(value): + return value[1] + + +print(double("22")) +# I predicted that it would return an error, but it actually returned 2222. +# I didn't expect this because I thought double() was supposed to work only with numbers. \ No newline at end of file From 4b082acd81b15e6d5594ad6d72ae4252cc6d5660 Mon Sep 17 00:00:00 2001 From: shreefAhmedM Date: Sun, 9 Aug 2026 12:43:05 +0100 Subject: [PATCH 02/13] Limits of type checking --- sprint5-prep-exercises/LimiOfTypeCheck.py | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 sprint5-prep-exercises/LimiOfTypeCheck.py diff --git a/sprint5-prep-exercises/LimiOfTypeCheck.py b/sprint5-prep-exercises/LimiOfTypeCheck.py new file mode 100644 index 000000000..9f7a5e528 --- /dev/null +++ b/sprint5-prep-exercises/LimiOfTypeCheck.py @@ -0,0 +1,7 @@ +def double(number): + # return number * 3 + return number * 2 + +print(double(10)) +# The bug is that the double function multiplies the number by 3 instead of 2. +# Since the function is called double, it should multiply the number by 2. \ No newline at end of file From e437bab6decf912b75a64a95c9217ae22504a93a Mon Sep 17 00:00:00 2001 From: shreefAhmedM Date: Sun, 9 Aug 2026 16:53:22 +0100 Subject: [PATCH 03/13] Running the code through mypy, and fix all of the bugs that show up --- sprint5-prep-exercises/typeAnnotations.py | 35 +++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 sprint5-prep-exercises/typeAnnotations.py diff --git a/sprint5-prep-exercises/typeAnnotations.py b/sprint5-prep-exercises/typeAnnotations.py new file mode 100644 index 000000000..5aeb69840 --- /dev/null +++ b/sprint5-prep-exercises/typeAnnotations.py @@ -0,0 +1,35 @@ + +def open_account(balances: dict[str, int], name: str, amount: int): + 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}") \ No newline at end of file From 8c9cd800678e6ca7b47a832df2d84a3624f6f60b Mon Sep 17 00:00:00 2001 From: shreefAhmedM Date: Sun, 9 Aug 2026 17:27:14 +0100 Subject: [PATCH 04/13] understanding mypy error message --- sprint5-prep-exercises/classesAndObjects.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 sprint5-prep-exercises/classesAndObjects.py diff --git a/sprint5-prep-exercises/classesAndObjects.py b/sprint5-prep-exercises/classesAndObjects.py new file mode 100644 index 000000000..6d333ffd7 --- /dev/null +++ b/sprint5-prep-exercises/classesAndObjects.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 From aad3e376522e8139b2c4a0c515686ea2996231ac Mon Sep 17 00:00:00 2001 From: shreefAhmedM Date: Tue, 11 Aug 2026 13:49:40 +0100 Subject: [PATCH 05/13] Change the Person class to take a date of birth --- sprint5-prep-exercises/accessNotExiProp.py | 11 ++++++++++ sprint5-prep-exercises/classesAndObjects.py | 6 +++++- sprint5-prep-exercises/methods.py | 23 +++++++++++++++++++++ sprint5-prep-exercises/typeAnnotations.py | 6 +++++- 4 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 sprint5-prep-exercises/accessNotExiProp.py create mode 100644 sprint5-prep-exercises/methods.py diff --git a/sprint5-prep-exercises/accessNotExiProp.py b/sprint5-prep-exercises/accessNotExiProp.py new file mode 100644 index 000000000..5be277df5 --- /dev/null +++ b/sprint5-prep-exercises/accessNotExiProp.py @@ -0,0 +1,11 @@ +class Person: + def __init__(self, name: str): + self.name = name + +def get_name(person: Person) -> str: + return person.name + +def get_age(person: Person) -> int: + return person.age +# As I expected, mypy prints an error saying that Person has no attribute name, +# because the age property does not exist in the Person class. \ No newline at end of file diff --git a/sprint5-prep-exercises/classesAndObjects.py b/sprint5-prep-exercises/classesAndObjects.py index 6d333ffd7..2cfe36f78 100644 --- a/sprint5-prep-exercises/classesAndObjects.py +++ b/sprint5-prep-exercises/classesAndObjects.py @@ -10,4 +10,8 @@ def __init__(self, name: str, age: int, preferred_operating_system: str): eliza = Person("Eliza", 34, "Arch Linux") print(eliza.name) -print(eliza.address) \ No newline at end of file +print(eliza.address) + + +# The error means that address doesn't exist in the Person class. We can only +# access attributes that were defined in the class, such as name, age, and preferred_operating_system. \ No newline at end of file diff --git a/sprint5-prep-exercises/methods.py b/sprint5-prep-exercises/methods.py new file mode 100644 index 000000000..f449f9c88 --- /dev/null +++ b/sprint5-prep-exercises/methods.py @@ -0,0 +1,23 @@ +import datetime as dt +from dataclasses import dataclass + + +@dataclass +class Person: + name: str + birthdate: dt.date + preferred_operating_system: str + + def is_adult(self) -> bool: + today = dt.date.today() + age = today.year - self.birthdate.year + + if (today.month, today.day) < (self.birthdate.month, self.birthdate.day): + age -= 1 + + return age >= 18 + + +imran = Person("Imran", dt.date(2000, 8, 6), "Ubuntu") + +print(imran.is_adult()) \ No newline at end of file diff --git a/sprint5-prep-exercises/typeAnnotations.py b/sprint5-prep-exercises/typeAnnotations.py index 5aeb69840..cdb4f1742 100644 --- a/sprint5-prep-exercises/typeAnnotations.py +++ b/sprint5-prep-exercises/typeAnnotations.py @@ -32,4 +32,8 @@ def format_pence_as_string(total_pence: int) -> str: total_pence = sum_balances(balances) total_string = format_pence_as_string(total_pence) -print(f"The bank accounts total {total_string}") \ No newline at end of file +print(f"The bank accounts total {total_string}") +def is_adult(person: Person) -> bool: + return person.age >= 18 + +print(is_adult(imran)) \ No newline at end of file From 45b9d4c06bd44643a3e7a5d0a809f411845e7c06 Mon Sep 17 00:00:00 2001 From: shreefAhmedM Date: Tue, 11 Aug 2026 14:38:20 +0100 Subject: [PATCH 06/13] changing the type annotation of Person.preferred_operating_system from str to List[str] --- sprint5-prep-exercises/prefOperatingSys.py | 42 ++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 sprint5-prep-exercises/prefOperatingSys.py diff --git a/sprint5-prep-exercises/prefOperatingSys.py b/sprint5-prep-exercises/prefOperatingSys.py new file mode 100644 index 000000000..a63acde5a --- /dev/null +++ b/sprint5-prep-exercises/prefOperatingSys.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 == 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}") \ No newline at end of file From 6991373bbdf9f33953e5dd59f866f6a5df1042df Mon Sep 17 00:00:00 2001 From: shreefAhmedM Date: Tue, 11 Aug 2026 22:37:58 +0100 Subject: [PATCH 07/13] implementing a program about a library has to lend out --- sprint5-prep-exercises/enums.py | 96 +++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 sprint5-prep-exercises/enums.py diff --git a/sprint5-prep-exercises/enums.py b/sprint5-prep-exercises/enums.py new file mode 100644 index 000000000..a133d0799 --- /dev/null +++ b/sprint5-prep-exercises/enums.py @@ -0,0 +1,96 @@ +from dataclasses import dataclass +from enum import Enum +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 + + +laptops = [ + Laptop(1, "Dell", "XPS", 13, OperatingSystem.ARCH), + Laptop(2, "Dell", "XPS", 15, OperatingSystem.UBUNTU), + Laptop(3, "Dell", "XPS", 15, OperatingSystem.UBUNTU), + Laptop(4, "Apple", "MacBook", 13, OperatingSystem.MACOS), +] + + +# Get the person's name +name = input("What is your name? ") + + +# Get and convert age +try: + age = int(input("What is your age? ")) +except ValueError: + print("Age must be a number.", file=sys.stderr) + sys.exit(1) + + +# Get and convert operating system +try: + os_input = input("What is your preferred operating system? ") + operating_system = OperatingSystem(os_input) +except ValueError: + print("Invalid operating system.", file=sys.stderr) + sys.exit(1) + + +person = Person( + name=name, + age=age, + preferred_operating_system=operating_system, +) + + +# Count laptops with the person's preferred OS +number_available = sum( + laptop.operating_system == person.preferred_operating_system + for laptop in laptops +) + + +print( + f"We have {number_available} laptop(s) with " + f"{person.preferred_operating_system.value}." +) + + +# Find the operating system with the most laptops +counts = {} + +for os in OperatingSystem: + counts[os] = sum( + laptop.operating_system == os + for laptop in laptops + ) + + +most_available_os = max(counts, key=counts.get) + + +if most_available_os != person.preferred_operating_system: + if counts[most_available_os] > number_available: + print( + f"If you are willing to use {most_available_os.value}, " + f"you are more likely to get a laptop because we have " + f"{counts[most_available_os]} available." + ) \ No newline at end of file From f4dfc058e2380ab415177b5a43fdab69efd03ba5 Mon Sep 17 00:00:00 2001 From: shreefAhmedM Date: Wed, 12 Aug 2026 10:26:10 +0100 Subject: [PATCH 08/13] comments that explain what each line does in predictInheritance.py --- sprint5-prep-exercises/PredictInheritance.py | 58 ++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 sprint5-prep-exercises/PredictInheritance.py diff --git a/sprint5-prep-exercises/PredictInheritance.py b/sprint5-prep-exercises/PredictInheritance.py new file mode 100644 index 000000000..beb48aaad --- /dev/null +++ b/sprint5-prep-exercises/PredictInheritance.py @@ -0,0 +1,58 @@ +# Parent class stores a person's first name and last name +class Parent: + def __init__(self, first_name: str, last_name: str): + self.first_name = first_name + self.last_name = last_name + # Returns the person's first and last name together + def get_name(self) -> str: + return f"{self.first_name} {self.last_name}" + +# Child inherits the fields and methods from Parent +# It also allows the person to change their last name +class Child(Parent): + def __init__(self, first_name: str, last_name: str): + super().__init__(first_name, last_name) + self.previous_last_names = [] + # Changes the last name and saves the old name + def change_last_name(self, last_name) -> None: + self.previous_last_names.append(self.last_name) + self.last_name = last_name + # Returns the current name and the original 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}" +# Create child object +person1 = Child("Elizaveta", "Alekseeva") +# Child inherits get_name() from Parent +# Output: Elizaveta Alekseeva +print(person1.get_name()) +# Child has its own get_full_name() method +# Output: Elizaveta Alekseeva +print(person1.get_full_name()) +# Change the last name +person1.change_last_name("Tyurina") +# The current last name is now Tyurina +# Output: Elizaveta Tyurina +print(person1.get_name()) +# Shows the new name and the previous last name +# Output: Elizaveta Tyurina (née Alekseeva) +print(person1.get_full_name()) +# Create a Parent object +person2 = Parent("Elizaveta", "Alekseeva") +# Parent has get_name(), so this works +# Output: Elizaveta Alekseeva +print(person2.get_name()) +# This causes an AttributeError because Parent +# does not have a get_full_name() method +print(person2.get_full_name()) +# This also causes an AttributeError because Parent +# does not have a change_last_name() method +person2.change_last_name("Tyurina") +# get_name() still works because it belongs to Parent +# Output: Elizaveta Alekseeva +print(person2.get_name()) +# This would cause another AttributeError +# because get_full_name() only exists in Child +print(person2.get_full_name()) \ No newline at end of file From 9f25002aab33392a6520d85a0bbe25ddeb352b22 Mon Sep 17 00:00:00 2001 From: shreefAhmedM Date: Wed, 12 Aug 2026 11:51:15 +0100 Subject: [PATCH 09/13] refactoring the code --- sprint5-prep-exercises/prefOperatingSys.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sprint5-prep-exercises/prefOperatingSys.py b/sprint5-prep-exercises/prefOperatingSys.py index a63acde5a..0532fd461 100644 --- a/sprint5-prep-exercises/prefOperatingSys.py +++ b/sprint5-prep-exercises/prefOperatingSys.py @@ -39,4 +39,10 @@ def find_possible_laptops(laptops: List[Laptop], person: Person) -> List[Laptop] 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}") + + + + # Yes, at first, when I changed str to list[str], + # mypy showed errors as I expected because I was still passing strings instead of lists + # Then I changed the field name to the plural form `preferred_operating_systems` to match the fact that it is now a list. From af4fe85a6f8c792444ce85b96879606699919e99 Mon Sep 17 00:00:00 2001 From: shreefAhmedM Date: Fri, 14 Aug 2026 08:20:42 +0100 Subject: [PATCH 10/13] adding methodsAndFunctions.tx file --- sprint5-prep-exercises/methodsAndFunctions.txt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 sprint5-prep-exercises/methodsAndFunctions.txt diff --git a/sprint5-prep-exercises/methodsAndFunctions.txt b/sprint5-prep-exercises/methodsAndFunctions.txt new file mode 100644 index 000000000..4f7036323 --- /dev/null +++ b/sprint5-prep-exercises/methodsAndFunctions.txt @@ -0,0 +1,17 @@ +Advantages of Using Methods Instead of Free Functions +# Easier to maintain + Methods keep related operations inside the class, making the program more organized and easier to update. +# Better data protection + A method can control how the object's data is changed and prevent invalid changes. +# Simple to use + Methods can be called using dot notation, such as account.deposit(100), which makes the code easy to read. +# Hides unnecessary details + Users only need to know what a method does and how to call it. They don't need to understand all the code inside it. +# Keeps data and behaviour together + A class can contain both the information about an object and the methods that work with that information. +# Can be reused with different objects + Once a method is defined in a class, objects created from that class can use the same method. +# Allows rules to be enforced + Methods can make sure that data is changed in a safe and valid way. For example, a withdraw() method could prevent a bank account from having a negative balance. +In short: methods are useful because they make code more organized, +reusable, easier to understand, and safer to manage, especially when working with objects and their data. From 172f9c60af5e92522f0c4183b766fec59fdae1f0 Mon Sep 17 00:00:00 2001 From: shreefAhmedM Date: Fri, 14 Aug 2026 08:46:00 +0100 Subject: [PATCH 11/13] adding the missing code in typeAnnotation.py file --- sprint5-prep-exercises/generics.py | 20 ++++++++++++++++++++ sprint5-prep-exercises/typeAnnotations.py | 17 ++++------------- 2 files changed, 24 insertions(+), 13 deletions(-) create mode 100644 sprint5-prep-exercises/generics.py diff --git a/sprint5-prep-exercises/generics.py b/sprint5-prep-exercises/generics.py new file mode 100644 index 000000000..0f857f27a --- /dev/null +++ b/sprint5-prep-exercises/generics.py @@ -0,0 +1,20 @@ +from dataclasses import dataclass +from typing import List + +@dataclass(frozen=True) +class Person: + name: str + children: List["Person"] + age: int + +fatma = Person(name="Fatma", children=[], age=10) +aisha = Person(name="Aisha", children=[], age=13) + +imran = Person(name="Imran", children=[fatma, aisha], age=50) + +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) \ No newline at end of file diff --git a/sprint5-prep-exercises/typeAnnotations.py b/sprint5-prep-exercises/typeAnnotations.py index cdb4f1742..42ddc6920 100644 --- a/sprint5-prep-exercises/typeAnnotations.py +++ b/sprint5-prep-exercises/typeAnnotations.py @@ -1,16 +1,13 @@ - -def open_account(balances: dict[str, int], name: str, amount: int): +from typing import Dict +def open_account(balances: dict, name: str, amount: int)-> None: balances[name] = amount - - -def sum_balances(accounts: dict[str, int]) -> int: +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" @@ -18,14 +15,12 @@ def format_pence_as_string(total_pence: int) -> str: pence = total_pence % 100 return f"£{pounds}.{pence:02d}" - -balances: dict[str, int] = { +balances = { "Sima": 700, "Linn": 545, "Georg": 831, } - open_account(balances, "Tobi", 913) open_account(balances, "Olya", 713) @@ -33,7 +28,3 @@ def format_pence_as_string(total_pence: int) -> str: total_string = format_pence_as_string(total_pence) print(f"The bank accounts total {total_string}") -def is_adult(person: Person) -> bool: - return person.age >= 18 - -print(is_adult(imran)) \ No newline at end of file From e9ba778824cea30078ae62ee0b4717f10e98f228 Mon Sep 17 00:00:00 2001 From: shreefAhmedM Date: Fri, 14 Aug 2026 08:53:57 +0100 Subject: [PATCH 12/13] refactoring prefOpratingSys.py file --- sprint5-prep-exercises/prefOperatingSys.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sprint5-prep-exercises/prefOperatingSys.py b/sprint5-prep-exercises/prefOperatingSys.py index 0532fd461..c957aae9c 100644 --- a/sprint5-prep-exercises/prefOperatingSys.py +++ b/sprint5-prep-exercises/prefOperatingSys.py @@ -20,7 +20,7 @@ class Laptop: def find_possible_laptops(laptops: List[Laptop], person: Person) -> List[Laptop]: possible_laptops = [] for laptop in laptops: - if laptop.operating_system == person.preferred_operating_systems: + if laptop.operating_system in person.preferred_operating_systems: possible_laptops.append(laptop) return possible_laptops @@ -41,8 +41,6 @@ def find_possible_laptops(laptops: List[Laptop], person: Person) -> List[Laptop] possible_laptops = find_possible_laptops(laptops, person) print(f"Possible laptops for {person.name}: {possible_laptops}") - - # Yes, at first, when I changed str to list[str], # mypy showed errors as I expected because I was still passing strings instead of lists # Then I changed the field name to the plural form `preferred_operating_systems` to match the fact that it is now a list. From 1b2d91c7019221419771ca0f0cfab85466f9a6db Mon Sep 17 00:00:00 2001 From: shreefAhmedM Date: Fri, 14 Aug 2026 09:09:16 +0100 Subject: [PATCH 13/13] inhancing the UI and validation in enums.py file --- sprint5-prep-exercises/enums.py | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/sprint5-prep-exercises/enums.py b/sprint5-prep-exercises/enums.py index a133d0799..6d3c532fa 100644 --- a/sprint5-prep-exercises/enums.py +++ b/sprint5-prep-exercises/enums.py @@ -33,11 +33,8 @@ class Laptop: ] -# Get the person's name name = input("What is your name? ") - -# Get and convert age try: age = int(input("What is your age? ")) except ValueError: @@ -45,11 +42,19 @@ class Laptop: sys.exit(1) -# Get and convert operating system +print("Available operating systems:") +for os in OperatingSystem: + print(os.value) + try: - os_input = input("What is your preferred operating system? ") - operating_system = OperatingSystem(os_input) -except ValueError: + os_input = input("What is your preferred operating system? ").strip().lower() + + operating_system = next( + os for os in OperatingSystem + if os.value.lower() == os_input + ) + +except StopIteration: print("Invalid operating system.", file=sys.stderr) sys.exit(1) @@ -61,21 +66,18 @@ class Laptop: ) -# Count laptops with the person's preferred OS number_available = sum( laptop.operating_system == person.preferred_operating_system for laptop in laptops ) - print( f"We have {number_available} laptop(s) with " f"{person.preferred_operating_system.value}." ) -# Find the operating system with the most laptops -counts = {} +counts: dict[OperatingSystem, int] = {} for os in OperatingSystem: counts[os] = sum( @@ -86,7 +88,6 @@ class Laptop: most_available_os = max(counts, key=counts.get) - if most_available_os != person.preferred_operating_system: if counts[most_available_os] > number_available: print(