generated from CodeYourFuture/Module-Template
-
-
Notifications
You must be signed in to change notification settings - Fork 21
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
Open
AFatmaa
wants to merge
11
commits into
CodeYourFuture:main
Choose a base branch
from
AFatmaa:prep-exercises
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
1c36396
Add exercise on why we use types with predictions and results
AFatmaa 3ea0bc5
Add mypy type checking exercise with type annotations and fixes
AFatmaa 5897bbe
Add classes and objects exercise with type checking examples
AFatmaa 19d3bed
Add methods exercises: advantages of methods and Person class using d…
AFatmaa e9e8d65
Add dataclass example for Person with date_of_birth and is_adult method
AFatmaa ce71241
Add generics exercise using List[Person] for type-safe children attri…
AFatmaa c287d6b
Use type checking to guide refactoring: change OS field to a list of …
AFatmaa 65ea661
Add enum-based program for laptop OS preferences and user input valid…
AFatmaa 51af61d
Add inheritance example with Parent and Child classes demonstrating s…
AFatmaa 6820eb3
chore: add explanation comment
AFatmaa d542bc4
feat: calculate age automatically based on birth year
AFatmaa File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| # Python | ||
| __pycache__/ | ||
| .mypy_cache/ | ||
| .venv/ | ||
|
|
||
| # Node | ||
| node_modules/ | ||
|
|
||
| # Mac | ||
| .DS_Store |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| from dataclasses import dataclass | ||
| from typing import List | ||
| from datetime import date | ||
|
|
||
| @dataclass(frozen=True) | ||
| class Person: | ||
| name: str | ||
| birth_year: int | ||
| children: List["Person"] | ||
|
|
||
| @property | ||
| def age(self) -> int: | ||
| current_year = date.today().year | ||
| return current_year - self.birth_year | ||
|
|
||
| fatma = Person(name="Fatma", birth_year=2018, children=[]) | ||
| aisha = Person(name="Aisha", birth_year=2020, children=[]) | ||
| imran = Person(name="Imran", birth_year=1990, children=[fatma, aisha]) | ||
|
|
||
| def print_family_tree(person: Person) -> None: | ||
| print(f"{person.name} ({person.age})") | ||
| for child in person.children: | ||
| print(f"- {child.name} ({child.age})") | ||
|
|
||
| print_family_tree(imran) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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}") |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| 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. | ||
|
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 🙏 |
||
| # A better name would be 'triple' or 'multiply_by_three'. | ||
| # 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. | ||
|
|
||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.