-
-
Notifications
You must be signed in to change notification settings - Fork 30
London | 25-SDC-July | Fatma Arslantas | Sprint 4 | Prep exercises #55
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 9 commits
1c36396
3ea0bc5
5897bbe
19d3bed
e9e8d65
ce71241
c287d6b
65ea661
51af61d
6820eb3
d542bc4
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,27 @@ | ||
| 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") | ||
| eliza = Person("Eliza", 34, "Arch Linux") | ||
|
|
||
| print(imran.name) | ||
| # print(imran.address) # mypy error: Person has no attribute "address" | ||
|
|
||
| print(eliza.name) | ||
| # print(eliza.address) # mypy error again | ||
|
|
||
| def is_adult(person: Person) -> bool: | ||
| return person.age >= 18 | ||
|
|
||
| print(is_adult(imran)) # no mypy error | ||
|
|
||
| def print_address(person: Person) -> None: | ||
| print(person.address) # mypy will catch this too | ||
|
|
||
| # I learned that a class defines what attributes each object will have. | ||
| # Mypy can check if I try to access an attribute that doesn't exist. | ||
| # It helps to avoid mistakes like typing person.addres instead of person.address. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| 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: | ||
| today = date.today() | ||
| age = today.year - self.date_of_birth.year - ( | ||
| (today.month, today.day) < (self.date_of_birth.month, self.date_of_birth.day) | ||
| ) | ||
| return age >= 18 | ||
|
|
||
|
|
||
| imran = Person("Imran", date(2002, 5, 15), "Ubuntu") | ||
| imran2 = Person("Imran", date(2002, 5, 15), "Ubuntu") | ||
|
|
||
| print(imran) # Person(name='Imran', date_of_birth=datetime.date(2002, 5, 15), preferred_operating_system='Ubuntu') | ||
| print(imran == imran2) # True | ||
| print(imran.is_adult()) # True |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| import sys | ||
| from enum import Enum | ||
| from dataclasses import dataclass | ||
|
|
||
| class OperatingSystem(Enum): | ||
| MACOS = "macOS" | ||
| ARCH = "Arch Linux" | ||
| UBUNTU = "Ubuntu" | ||
|
|
||
| @dataclass(frozen=True) | ||
| class Laptop: | ||
| id: int | ||
| manufacturer: str | ||
| model: str | ||
| screen_size_in_inches: float | ||
| operating_system: OperatingSystem | ||
|
|
||
| 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="Apple", model="MacBook", screen_size_in_inches=13, operating_system=OperatingSystem.MACOS), | ||
| Laptop(id=4, manufacturer="Apple", model="MacBook Air", screen_size_in_inches=15, operating_system=OperatingSystem.MACOS), | ||
| ] | ||
|
|
||
| # user input | ||
| try: | ||
| name = input("Enter your name: ") | ||
| age = int(input("Enter your age: ")) | ||
| os_input = input("Enter your preferred operating system (macOS / Arch Linux / Ubuntu): ") | ||
|
|
||
| # Convert string to enum | ||
| preferred_os = OperatingSystem(os_input) | ||
| except ValueError: | ||
| print("Invalid input. Please check your age or operating system name.", file=sys.stderr) | ||
| sys.exit(1) | ||
|
|
||
| # count available laptops | ||
| matching_laptops = [l for l in laptops if l.operating_system == preferred_os] | ||
| print(f"{name}, there are {len(matching_laptops)} laptops available with {preferred_os.value}.") | ||
|
|
||
| # suggest alternative OS if another has more laptops | ||
| os_counts = { | ||
| os: sum(1 for l in laptops if l.operating_system == os) | ||
| for os in OperatingSystem | ||
| } | ||
|
|
||
| most_common_os = max(os_counts, key=lambda os: os_counts[os]) | ||
|
|
||
| if most_common_os != preferred_os: | ||
| print(f"If you can use {most_common_os.value}, you have a higher chance of getting a laptop.") | ||
|
|
||
|
|
||
| # I learned how to use Enums to make my code safer and avoid typos. | ||
| # I also learned how to handle invalid user input safely using try and except. | ||
| # Using lambda helps mypy understand the type more clearly. | ||
| # Without it, mypy didn't know what os_counts.get returns. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| 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=7, children=[]) | ||
| aisha = Person(name="Aisha", age=5, children=[]) | ||
| imran = Person(name="Imran", age=35, 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) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| 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): | ||
| # Call the parent class constructor | ||
| super().__init__(first_name, last_name) | ||
| self.previous_last_names = [] | ||
|
|
||
| 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()) # from Parent class | ||
| print(person1.get_full_name()) # from Child class | ||
|
|
||
| person1.change_last_name("Tyurina") | ||
| print(person1.get_name()) | ||
| print(person1.get_full_name()) | ||
|
|
||
| person2 = Parent("Elizaveta", "Alekseeva") | ||
| print(person2.get_name()) | ||
|
|
||
| # The next lines will cause errors, because Parent doesn't have these methods | ||
| # print(person2.get_full_name()) | ||
| # person2.change_last_name("Tyurina") | ||
|
|
||
| print(person2.get_name()) | ||
| # print(person2.get_full_name()) | ||
|
|
||
|
|
||
| # I learned that Parent and Child classes can have different methods — Parent can’t access methods only defined in Child | ||
| # I understood that the child class can add new methods or override existing ones | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| 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.is_adult()) # True | ||
|
|
||
| # Advantages of using methods instead of free functions: | ||
| # 1. Easier documentation - all related behaviors are attached to the class. | ||
| # 2. Encapsulation - data and logic are kept together in one place. | ||
| # 3. Easier maintenance - when class details change, methods can be updated easily. | ||
| # 4. Clearer code - you can write person.is_adult() instead of is_adult(person). |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| 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 - ( | ||
| (today.month, today.day) < (self.date_of_birth.month, self.date_of_birth.day) | ||
| ) | ||
| return age >= 18 | ||
|
|
||
|
|
||
| imran = Person("Imran", date(2002, 5, 15), "Ubuntu") | ||
| print(imran.is_adult()) # True | ||
|
|
||
| # I learned that methods can easily adapt to changes inside a class. | ||
| # Now the class stores a date of birth instead of age, but the method still works correctly. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 = { | ||
| "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}") |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| 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}") | ||
|
|
||
|
|
||
| # I learned how type checking helps when refactoring code. | ||
| # Mypy shows exactly which parts of the code need to change when we rename or change a field type. | ||
| # This makes large codebases easier to update safely. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| def half(value): | ||
| return value / 2 | ||
|
|
||
| def double(value): | ||
| return value * 2 | ||
|
|
||
| def second(value): | ||
| return value[1] | ||
|
|
||
|
|
||
| print(half(22)) # My prediction was correct. It returned 11 | ||
| # print(half("hello")) # My prediction was correct. It gave an error since it is a string | ||
| # print(half("22")) # # I thought maybe Python would see it as a number and return 11 | ||
|
|
||
|
|
||
| print(double(22)) # My prediction was correct. It returned 44 | ||
| print(double("hello")) # I expected an error | ||
| print(double("22")) # I thought maybe Python would treat it as a number and return 44 | ||
|
|
||
| # print(second(22)) # # My prediction was correct. It gave an error since it is a number | ||
| # print(second(0x16)) # # My prediction was correct. It gave an error | ||
| print(second("hello")) # My prediction was correct. It returned 'e' | ||
| print(second("22")) # My prediction was correct. It returned '2' | ||
|
|
||
| def double1(number): | ||
| return number * 3 | ||
|
|
||
| print(double1(10)) | ||
| # When you check the function name, it doesn’t fit what we have to expect. | ||
|
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 suggest a better name?
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. A better name would be triple, since it multiplies by 3. I’ve added a short comment in the code. Thanks 🙏 |
||
| # If you use this func you would expect it to give you double like 20, not 30. | ||
| # It might cause a problem for your code. | ||
|
|
||
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.
In this case, is there a difference between
person.addresandperson.address?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.
Yes, there is.
person.address would work only if the Person class actually had an attribute called address, but person.addres (with the typo) doesn’t exist. So mypy can catch that before running the code.