-
-
Notifications
You must be signed in to change notification settings - Fork 31
London | July SDC | Ali Qassab | Sprint 4 | Prep exercises #44
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 11 commits
7f56176
dd0aa3b
350e595
3b72b37
0ab20fb
f422356
76e3202
7c1f71d
b169d9d
8b0db4c
5bb7641
1f45822
099d936
380df70
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| # Virtual Environment | ||
| venv/ | ||
| env/ | ||
| ENV/ | ||
|
|
||
| # Python cache | ||
| __pycache__/ | ||
| *.pyc | ||
| *.pyo | ||
| *.pyd | ||
|
|
||
| # mypy cache | ||
| .mypy_cache/ | ||
|
|
||
| # IDE | ||
| .vscode/ | ||
| .idea/ | ||
| *.swp | ||
| *.swo | ||
|
|
||
| # OS | ||
| .DS_Store | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| 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(self) -> bool: | ||
| return self.age >= 18 | ||
|
|
||
|
|
||
| imran = Person("Imran", 22, "Ubuntu") | ||
| print(imran.name) | ||
| # print(imran.address) # Error: address is not an attribute | ||
| print(imran.is_adult()) | ||
|
|
||
| eliza = Person("Eliza", 34, "Arch Linux") | ||
| print(eliza.name) | ||
| # print(eliza.address) # Error: address is not an attribute | ||
|
|
||
|
|
||
| # This function will error at runtime if called | ||
| def get_address(person: Person) -> str: | ||
| return person.address # Error: Person has no attribute 'address' | ||
|
|
||
| # print(get_address(imran)) # Uncommenting this will cause an error | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| 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) -> bool: | ||
| current_date = date.today() | ||
| age = current_date.year - self.date_of_birth.year - ( | ||
| (current_date.month, current_date.day) < (self.date_of_birth.month, self.date_of_birth.day) | ||
| ) | ||
| return age >= 18 | ||
|
|
||
| # Example usage: | ||
| imran = Person("Imran", date(2001, 5, 15), "Ubuntu") | ||
| print(imran) | ||
| print(imran.is_adult()) | ||
|
|
||
| eliza = Person("Eliza", date(1990, 3, 20), "Arch Linux") | ||
| print(eliza) | ||
| print(eliza.is_adult()) | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| from dataclasses import dataclass | ||
| from enum import Enum | ||
|
|
||
| class OperatingSystem(Enum): | ||
| MACOS = "macOS" | ||
| UBUNTU = "Ubuntu" | ||
| ARCH = "Arch Linux" | ||
|
|
||
| @dataclass | ||
| class Laptop: | ||
| id: int | ||
| manufacturer: str | ||
| model: str | ||
| screen_size_in_inches: float | ||
| operating_system: OperatingSystem | ||
|
|
||
| laptops = [ | ||
| Laptop(id=1, manufacturer="Lenovo", model="ThinkPad", screen_size_in_inches=14, operating_system=OperatingSystem.ARCH), | ||
| Laptop(id=2, manufacturer="HP", model="Pavilion", screen_size_in_inches=15.6, operating_system=OperatingSystem.UBUNTU), | ||
| Laptop(id=3, manufacturer="Asus", model="ZenBook", screen_size_in_inches=13.3, operating_system=OperatingSystem.UBUNTU), | ||
| Laptop(id=4, manufacturer="Apple", model="MacBook Air", screen_size_in_inches=13, operating_system=OperatingSystem.MACOS), | ||
| ] | ||
|
|
||
| @dataclass | ||
| class Person: | ||
| name: str | ||
| age: int | ||
| preferred_operating_system: OperatingSystem | ||
|
|
||
|
|
||
| name = input('Please enter your name: ') | ||
|
|
||
| age_input = input('Please enter your age: ') | ||
| try: | ||
| age = int(age_input) | ||
| except ValueError: | ||
| print(f"Error: '{age_input}' is not a valid age. Please enter a number.") | ||
| exit() | ||
|
|
||
| preferred_os_input = input('Please enter your preferred operating system: ') | ||
| try: | ||
| preferred_operating_system = OperatingSystem(preferred_os_input) | ||
| except ValueError: | ||
| available_options = ', '.join([os.value for os in OperatingSystem]) | ||
| print(f"Error: '{preferred_os_input}' is not available. Please choose from: {available_options}") | ||
| exit() | ||
|
|
||
|
|
||
| person = Person(name=name, age=age, preferred_operating_system=preferred_operating_system) | ||
|
|
||
|
|
||
| number_of_available_laptops = sum( | ||
| 1 for laptop in laptops if laptop.operating_system == person.preferred_operating_system | ||
| ) | ||
|
|
||
| def offer_laptop_to_user() -> None: | ||
| offer = input('Would you like a laptop with this OS (yes / no) ? ') | ||
| if offer.lower() == "y" or offer.lower() == "yes": | ||
| print('Great! Please come on monday next week to collect your laptop') | ||
| else: | ||
| print('No problem. See you later.') | ||
|
|
||
| if number_of_available_laptops == 1: | ||
| print(f'There is {number_of_available_laptops} laptop available with your preferred operating system.') | ||
| offer_laptop_to_user() | ||
| elif number_of_available_laptops > 1: | ||
| print(f'There are {number_of_available_laptops} laptops available with your preferred operating system.') | ||
| offer_laptop_to_user() | ||
| else: | ||
| print('There are no laptops available with your preferred operating system.') |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| from dataclasses import dataclass | ||
| from typing import List | ||
|
|
||
| @dataclass(frozen=True) | ||
| class Person: | ||
| name: str | ||
| age: int | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you solve this in a way that it always prints the current age, rather than hard-coding a specific age?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
| children: List["Person"] | ||
|
|
||
| sara = Person(name="Sara", age=5, children=[]) | ||
| ahmed = Person(name="Ahmed", age=8, children=[]) | ||
|
|
||
| ali = Person(name="Ali", age=28, children=[sara]) | ||
| aya = Person(name="Aya", age=32, children=[ahmed]) | ||
|
|
||
| imran = Person(name="Imran", age=55, children=[ali, aya]) | ||
|
|
||
| def print_family_tree(person: Person) -> None: | ||
| print(f"{person.name} ({person.age})") | ||
| for child in person.children: | ||
| print(f" - {child.name} ({child.age})") | ||
| for grandchild in child.children: | ||
| print(f" - {grandchild.name} ({grandchild.age})") | ||
|
|
||
| def count_family_members(person: Person) -> int: | ||
| count = 1 | ||
| for child in person.children: | ||
| count += count_family_members(child) | ||
| return count | ||
|
|
||
| print_family_tree(imran) | ||
| print(f"\nTotal family members: {count_family_members(imran)}") | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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: 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}" | ||
|
|
||
|
|
||
| print("Creating Child instance:") | ||
| person1 = Child("Sarah", "Johnson") | ||
| print(f"Name: {person1.get_name()}") | ||
| print(f"Full name: {person1.get_full_name()}") | ||
|
|
||
| print("\nChanging last name to Smith:") | ||
| person1.change_last_name("Smith") | ||
| print(f"Name: {person1.get_name()}") | ||
| print(f"Full name: {person1.get_full_name()}") | ||
|
|
||
| print("\nCreating Parent instance:") | ||
| person2 = Parent("Emma", "Wilson") | ||
| print(f"Name: {person2.get_name()}") | ||
|
|
||
| # person2.change_last_name("Brown") # Error: Parent doesn't have change_last_name method |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| from datetime import date | ||
|
|
||
| class Person: | ||
| def __init__(self, name: str, DoB: date, preferred_operating_system: str): | ||
| self.name = name | ||
| self.DoB = DoB | ||
| self.preferred_operating_system = preferred_operating_system | ||
|
|
||
| def is_adult(self) -> bool: | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is a benefit or drawback of writing the function this way?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Stores DoB (fixed), not age (changes over time), so is_adult() stays correct. |
||
| current_date = date.today() | ||
| age = current_date.year - self.DoB.year - ( | ||
| (current_date.month, current_date.day) < (self.DoB.month, self.DoB.day) | ||
| ) | ||
| return age >= 18 | ||
|
|
||
|
|
||
|
|
||
| eliza = Person("Eliza", date(2010, 5, 15), "Arch Linux") | ||
| print(f"{eliza.name} is adult: {eliza.is_adult()}") | ||
|
|
||
| sara = Person("Sara", date(1995, 12, 20), "macOS") | ||
| print(f"{sara.name} is adult: {sara.is_adult()}") | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| mypy==1.18.2 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| 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, | ||
| } | ||
|
|
||
| # Bugs fixed: | ||
| # 1. Added balances as first argument | ||
| # 2. Converted amounts to pence (int) | ||
| # 3. Fixed function name typo | ||
| 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}") |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| from dataclasses import dataclass | ||
| from typing import Optional | ||
|
|
||
| # Before refactoring - unclear types | ||
| def process_user_data(data): | ||
| name = data[0] | ||
| age = data[1] | ||
| email = data[2] if len(data) > 2 else None | ||
|
|
||
| if age < 18: | ||
| return None | ||
|
|
||
| return f"{name} ({age}): {email or 'no email'}" | ||
|
|
||
|
|
||
| # After refactoring - clear types | ||
| @dataclass | ||
| class User: | ||
| name: str | ||
| age: int | ||
| email: Optional[str] = None | ||
|
|
||
| def is_adult(user: User) -> bool: | ||
| return user.age >= 18 | ||
|
|
||
| def format_user_info(user: User) -> str: | ||
| email_str = user.email if user.email else "no email" | ||
| return f"{user.name} ({user.age}): {email_str}" | ||
|
|
||
| def process_user(user: User) -> Optional[str]: | ||
| if not is_adult(user): | ||
| return None | ||
| return format_user_info(user) | ||
|
|
||
|
|
||
| # Testing old version | ||
| print(process_user_data(("Alice", 25, "alice@example.com"))) | ||
| print(process_user_data(("Bob", 16))) | ||
|
|
||
| # Testing new version | ||
| user1 = User("Alice", 25, "alice@example.com") | ||
| user2 = User("Bob", 16) | ||
|
|
||
| print(process_user(user1)) | ||
| print(process_user(user2)) | ||
|
|
||
|
|
||
| # Another example | ||
| def get_value(key: str, data: dict[str, int]) -> Optional[int]: | ||
| return data.get(key) | ||
|
|
||
| sample_data = {"a": 1, "b": 2} | ||
| result = get_value("a", sample_data) | ||
| if result is not None: | ||
| print(f"Found: {result}") |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| def half(value): | ||
| return value / 2 | ||
|
|
||
| def double(value): | ||
| return value * 2 | ||
|
|
||
| def second(value): | ||
| return value[1] | ||
|
|
||
| # Prediction: double("22") will return "2222" because * operator repeats strings | ||
| print(double("22")) | ||
|
|
||
| # Testing other cases | ||
| print(half(22)) | ||
| # print(half("hello")) # This will error | ||
| # print(half("22")) # This will error | ||
|
|
||
| print(double(22)) | ||
| print(double("hello")) | ||
|
|
||
| # print(second(22)) # This will error | ||
| print(second("hello")) | ||
| print(second("22")) | ||
|
|
||
| # The bug: this function is called double but multiplies by 3! | ||
| def double_bug(number): | ||
| return number * 3 | ||
|
|
||
| print(double_bug(10)) # Should return 20 but returns 30 | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can you think of any change you could make to this function to fix the bug?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Change number * 3 to number * 2 so the function doubles the input. |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you suggest a change that would fix this error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add an address parameter to the Person class init and stored it as self.address