diff --git a/prep-exercises/.gitignore b/prep-exercises/.gitignore new file mode 100644 index 00000000..18bfee67 --- /dev/null +++ b/prep-exercises/.gitignore @@ -0,0 +1,2 @@ +.venv + diff --git a/prep-exercises/exercise_eight.py b/prep-exercises/exercise_eight.py new file mode 100644 index 00000000..d110ad8b --- /dev/null +++ b/prep-exercises/exercise_eight.py @@ -0,0 +1,24 @@ +#Write a Person class using @datatype which uses a datetime.date for date of birth, rather than an +#int for age. + +#Re-add the is_adult method to it. + + +from datetime import date +from dataclasses import dataclass + +@dataclass +class Person: + name: str + date_of_birth: date + preferred_operating_system: str + + def is_adult(self) ->bool: + age_in_days = (date.today() - self.date_of_birth).days + age_in_years = age_in_days / 365.2425 + return age_in_years >= 18 + + + +imran = Person("Imran", date(2003,12, 3), "Ubuntu") +print(imran.is_adult()) diff --git a/prep-exercises/exercise_eleven.py b/prep-exercises/exercise_eleven.py new file mode 100644 index 00000000..dadef346 --- /dev/null +++ b/prep-exercises/exercise_eleven.py @@ -0,0 +1,122 @@ +#Write a program which: + +#1.Already has a list of Laptops that a library has to lend out. +#2.Accepts user input to create a new Person - it should use the input function to read a person’s +#name, age, and preferred operating system. +#3.Tells the user how many laptops the library has that have that operating system. +#4.If there is an operating system that has more laptops available, tells the user that if they’re willing to +#accept that operating system they’re more likely to get a laptop. + +#You should convert the age and preferred operating system input from the user into more constrained +#types as quickly as possible, and should output errors to stderr and terminate the program with a non- +#zero exit code if the user input bad values. + +from dataclasses import dataclass +import sys +from enum import Enum + +class operatingSystem(Enum): + CHROMEOS = "ChromeOS" + WINDOWS = "Windows" + MACOS = "macOS" + LINUX = "Linux" + ARCH = "Arch Linux" + UBUNTU = "Ubuntu" + + + +@dataclass(frozen=True) +class Person: + name: str + age: int + preferred_operating_system: str + + +@dataclass(frozen=True) +class Laptop: + id: int + manufacturer: str + model: str + screen_size_in_inches: float + operating_system: operatingSystem + + + +laptops = [ + Laptop(id=1, manufacturer="HP", model="Chromebook Plus 514", screen_size_in_inches=14, operating_system=operatingSystem.CHROMEOS), + Laptop(id=2, manufacturer="Microsoft", model="XPS", screen_size_in_inches=13.8, operating_system=operatingSystem.WINDOWS), + Laptop(id=3, manufacturer="Apple", model="MacBook Air", screen_size_in_inches=15, operating_system=operatingSystem.MACOS), + Laptop(id=4, manufacturer="Lenovo", model="ThinkPad X220", screen_size_in_inches=12.5, operating_system=operatingSystem.LINUX), + Laptop(id=5, manufacturer="Dell", model="XPS", screen_size_in_inches=13.7, operating_system=operatingSystem.ARCH), + Laptop(id=6, manufacturer="Dell", model="XPS", screen_size_in_inches=10.4, operating_system=operatingSystem.ARCH), + Laptop(id=7, manufacturer="Dell", model="XPS", screen_size_in_inches=15.5, operating_system=operatingSystem.UBUNTU), + Laptop(id=8, manufacturer="Dell", model="XPS", screen_size_in_inches=15, operating_system=operatingSystem.UBUNTU), + Laptop(id=9, manufacturer="Apple", model="MacBook", screen_size_in_inches=13.3, operating_system=operatingSystem.MACOS), +] + + +name_input = input("What's your name? ") +if not name_input.isalpha(): + print("Name must contain letters only!") + sys.exit(1) + +try: + age_input = int(input("What's your age? ")) +except ValueError: + print("Enter a numeric value for the age!") + sys.exit(1) + + +def parse_os_input(user_input: str) -> operatingSystem: + clean = user_input.lower().replace(" ", "") + + for os in operatingSystem: + if os.value.lower().replace(" ", "") == clean: + return os + print("Invalid operating system!", file=sys.stderr) + sys.exit(1) + +preferred_operating_system_input = parse_os_input(input("What's your preferred operating system? ")) + + + +def person_builder(name_input: str, age_input:int, preferred_operating_system_input:str) ->Person: + + return Person(name_input, age_input, preferred_operating_system_input) + + + +def laptops_counter(preferred_operating_system_input:str) ->int: + sum = 0 + for laptop in laptops: + if preferred_operating_system_input == laptop.operating_system: + sum += 1 + user_os = preferred_operating_system_input.value + if sum == 1: + return f"There is {sum} laptop with {user_os} operating system" + elif sum > 1: + return f"There are {sum} laptops with {user_os} operating system" + +print(laptops_counter(preferred_operating_system_input)) + + +user_os = preferred_operating_system_input + +def more_available_os(user_os: operatingSystem): + + os_counter = {} + for laptop in laptops: + os_counter[laptop.operating_system] = os_counter.get(laptop.operating_system, 0) + 1 + + max_count = max(os_counter.values()) + + user_os_count = os_counter.get(user_os, 0) + + if user_os_count < max_count: + most_available_os = max(os_counter, key=os_counter.get) + print(f"If you’re open to using {most_available_os.value} operating system, you’ll have a better chance of getting a laptop.”") + + +print(more_available_os(preferred_operating_system_input)) + + diff --git a/prep-exercises/exercise_five.py b/prep-exercises/exercise_five.py new file mode 100644 index 00000000..d4393d50 --- /dev/null +++ b/prep-exercises/exercise_five.py @@ -0,0 +1,46 @@ +# Add the is_adult code to the file you saved earlier. + +# Run it through mypy - notice that no errors are reported - mypy +# understands that Person has a property named age so is happy +# with the function. + +# Write a new function in the file that accepts a Person as a +# parameter and tries to access a property that doesn’t exist. Run +# it through mypy and check that it does report an error. + + +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) + + +def is_adult(person: Person) -> bool: + return person.age >= 18 + +print(is_adult(imran)) + + + +# New function: "is_engineer" takes "Person" as a parameter and tries to access "profession" - a property that does not exist. +def is_engineer(person: Person) -> bool: + return person.profession == "Engineer" + +print(is_engineer(eliza)) + +# After running through mypy, 2 errors related to the new function were reported: +# 1) exercise_five.py:36: error: Returning Any from function declared to return "bool" [no-any-return] +# since person does not have "profession" as attribute and thus its type is unknown, thus this function could be returning any type. Hence the error above. +# 2) exercise_five.py:36: error: "Person" has no attribute "profession" [attr-defined] +# The error above simply stating that attribute "profession" does not exist in the class "Person" + + diff --git a/prep-exercises/exercise_four.py b/prep-exercises/exercise_four.py new file mode 100644 index 00000000..e80d2aef --- /dev/null +++ b/prep-exercises/exercise_four.py @@ -0,0 +1,20 @@ +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) + +# Save the above code to a file, and run it through mypy. + +#Read the error, and make sure you understand what it’s telling you. + +# The error message simply says that the class: Person does not have "address" as an attribute. +# Therefore, the instances of the class: Person can not inheret an attribute that does not exist. \ No newline at end of file diff --git a/prep-exercises/exercise_nine.py b/prep-exercises/exercise_nine.py new file mode 100644 index 00000000..e9741f43 --- /dev/null +++ b/prep-exercises/exercise_nine.py @@ -0,0 +1,29 @@ +from dataclasses import dataclass +from typing import List + +@dataclass(frozen=True) +class Person: + name: str + #Add "age" attribute + age: int + children: List["Person"] + +#Add "age" field and thier respective values to "fatma" and "aisha" - instances of class "Person" +fatma = Person(name="Fatma", age=14, children=[]) +aisha = Person(name="Aisha",age=22, children=[]) + +##Add "age" field and its values to "imran" - instance of class "Person" +imran = Person(name="Imran", age=44, 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) + + +#Fix the above code so that it works. You must not change the print on line 17 - we do want to print the +#children’s ages. (Feel free to invent the ages of Imran’s children.) + + diff --git a/prep-exercises/exercise_one.py b/prep-exercises/exercise_one.py new file mode 100644 index 00000000..dcb2cec4 --- /dev/null +++ b/prep-exercises/exercise_one.py @@ -0,0 +1,11 @@ + +def double(value): + return value * 2 + +print(double("22")) + + +# 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? + +# Initial prediction was that a type coercion may take place and string "22" will convert to integer 22 and thus the function returns 44. +# After running the code, I now know that it did not do what i expected. It duplicated/repeated the string and returned 2222. diff --git a/prep-exercises/exercise_seven.py b/prep-exercises/exercise_seven.py new file mode 100644 index 00000000..d2bead6b --- /dev/null +++ b/prep-exercises/exercise_seven.py @@ -0,0 +1,28 @@ +#Change the Person class to take a date of birth (using the standard library’s datetime.date class) and +#store it in a field instead of age. + +#Update the is_adult method to act the same as before. + +from datetime import date + + +class Person: + def __init__(self, name: str, date_of_birth: date, preferred_operating_system: str): + self.name = name + self.preferred_operating_system = preferred_operating_system + #Add "date_of_birth" attribute to the "Person" class + self.date_of_birth = date_of_birth + + def is_adult(self) ->bool: + age_in_days = (date.today() - self.date_of_birth).days + age_in_years = age_in_days / 365.2425 + return age_in_years >= 18 + + + + + +imran = Person("Imran", date(2003,12, 3), "Ubuntu") +print(imran.is_adult()) + + diff --git a/prep-exercises/exercise_six.py b/prep-exercises/exercise_six.py new file mode 100644 index 00000000..a50851a8 --- /dev/null +++ b/prep-exercises/exercise_six.py @@ -0,0 +1,6 @@ +#Think of the advantages of using methods instead of free functions. Write them down in your notebook. + +# Easy and direct to data and thus more efficient when working on them. +# it's more reusable since all instances of a class inheret those methods defined in it automatically. +# you'll be less prone to make mistakes when using methods as part of a class/isntance of it as opposed to a free function attempting to aceess the class data. +# code is more organised and readable when methods are part of a class as opposed to when they're just free functions. diff --git a/prep-exercises/exercise_ten.py b/prep-exercises/exercise_ten.py new file mode 100644 index 00000000..76d1ecae --- /dev/null +++ b/prep-exercises/exercise_ten.py @@ -0,0 +1,56 @@ +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: + for item in person.preferred_operating_systems: + if laptop.operating_system == item: + possible_laptops.append(laptop) + return possible_laptops + + +people = [ + Person(name="Imran", age=22, preferred_operating_systems=["Ubuntu", "Arch Linux", "macOS"]), + Person(name="Eliza", age=34, preferred_operating_systems=["Arch Linux", "macOS", "Ubuntu"]), +] + +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}") + + +#Try changing the type annotation of Person.preferred_operating_system from str to List[str]. + +#Run mypy on the code. + +#It tells us different places that our code is now wrong, because we’re passing values of the wrong type. + +#We probably also want to rename our field - lists are plural. Rename the field to preferred_operating_systems. + +#Run mypy again. + +#Fix all of the places that mypy tells you need changing. Make sure the program works as you’d expect. \ No newline at end of file diff --git a/prep-exercises/exercise_three.py b/prep-exercises/exercise_three.py new file mode 100644 index 00000000..57e4c69e --- /dev/null +++ b/prep-exercises/exercise_three.py @@ -0,0 +1,40 @@ +#Do not run the following code. + +#This code contains bugs related to types. They are bugs mypy can catch. + +#Read this code to understand what it’s trying to do. Add type annotations to the method parameters and +#return types of this code. Run the code through mypy, and fix all of the bugs that show up. When you’re +#confident all of the type annotations are correct, and the bugs are fixed, run the code and check it works. + +from typing import Dict + +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", 9) +open_account(balances, "Olya", 7) + +total_pence = sum_balances(balances) +total_string = format_pence_as_string(total_pence) + +print(f"The bank accounts total {total_string}") diff --git a/prep-exercises/exercise_twelve.py b/prep-exercises/exercise_twelve.py new file mode 100644 index 00000000..483d375d --- /dev/null +++ b/prep-exercises/exercise_twelve.py @@ -0,0 +1,46 @@ + +#Play computer with this code. Predict what you expect each line will do. Then run the code and check +#your predictions. (If any lines cause errors, you may need to comment them out to check later lines). + +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()) + + +# I pridict that lines 38, 39, & 41 will through an error, since these methods simply don't exist in the parent class. + +# all problematic lines: 38, 39, 41 were commented one after the other while going through the error messages. \ No newline at end of file diff --git a/prep-exercises/exercise_two.py b/prep-exercises/exercise_two.py new file mode 100644 index 00000000..7533645f --- /dev/null +++ b/prep-exercises/exercise_two.py @@ -0,0 +1,26 @@ +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? + +# the bug here is logical: the function name: "double" - which contradicts what it does. +# Named double but it triples the parameter passed. +# To fix it either do: + +# A: +def double(number): + return number * 2 + +print(double(10)) + + +# or B: +def triple(number): + return number * 3 + +print(triple(10)) + + +