diff --git a/.gitignore b/.gitignore index 3c3629e6..ec685bab 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,5 @@ node_modules +implement-cowsay/.venv +**/package.json +**/package-lock.json +implement-cowsay/requirements.txt \ No newline at end of file diff --git a/number-systems/README.md b/number-systems/README.md deleted file mode 100644 index 77a3bde9..00000000 --- a/number-systems/README.md +++ /dev/null @@ -1,65 +0,0 @@ -Do not use any tools or programming to solve these problems. Work it out yourself by hand, and fill in the answers. - -Do not convert any binary numbers to decimal when solving a question unless the question explicitly tells you to. - -The goal of these exercises is for you to gain an intuition for binary numbers. Using tools to solve the problems defeats the point. - -Convert the decimal number 14 to binary. -Answer: - -Convert the binary number 101101 to decimal: -Answer: - -Which is larger: 1000 or 0111? -Answer: - -Which is larger: 00100 or 01011? -Answer: - -What is 10101 + 01010? -Answer: - -What is 10001 + 10001? -Answer: - -What's the largest number you can store with 4 bits, if you want to be able to represent the number 0? -Answer: - -How many bits would you need in order to store the numbers between 0 and 255 inclusive? -Answer: - -How many bits would you need in order to store the numbers between 0 and 3 inclusive? -Answer: - -How many bits would you need in order to store the numbers between 0 and 1000 inclusive? -Answer: - -How can you test if a binary number is a power of two (e.g. 1, 2, 4, 8, 16, ...)? -Answer: - -Convert the decimal number 14 to hex. -Answer: - -Convert the decimal number 386 to hex. -Answer: - -Convert the hex number 386 to decimal. -Answer: - -Convert the hex number B to decimal. -Answer: - -If reading the byte 0x21 as a number, what decimal number would it mean? -Answer: - -If reading the byte 0x21 as an ASCII character, what character would it mean? -Answer: - -If reading the byte 0x21 as a greyscale colour, as described in "Approaches for Representing Colors and Images", what colour would it mean? -Answer: - -If reading the bytes 0xAA00FF as an RGB colour, as described in "Approaches for Representing Colors and Images", what colour would it mean? -Answer: - -If reading the bytes 0xAA00FF as a sequence of three one-byte decimal numbers, what decimal numbers would they be? -Answer: diff --git a/prep-sprint5/class-object-person.py b/prep-sprint5/class-object-person.py new file mode 100644 index 00000000..a025ed0f --- /dev/null +++ b/prep-sprint5/class-object-person.py @@ -0,0 +1,40 @@ +''' +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)) + +''' adding the function:''' +def read_genre(person: Person) -> str: + if person.genre == "M": + return "Male" + else: + return "Female" + +''' returns: +cyf@cyfs-MacBook-Pro prep-sprint5 % mypy class-object-person.py +class-object-person.py:29: error: "Person" has no attribute "genre" [attr-defined] +Found 1 error in 1 file (checked 1 source file) + +''' diff --git a/prep-sprint5/dataclass-person.py b/prep-sprint5/dataclass-person.py new file mode 100644 index 00000000..c1c6a9ac --- /dev/null +++ b/prep-sprint5/dataclass-person.py @@ -0,0 +1,27 @@ +'''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 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_year = date.today().year + birth_year = self.date_of_birth.year + age = today_year - birth_year + + if date.today().month > self.date_of_birth.month: + return age >= 18 + elif date.today().month == self.date_of_birth.month: + return date.today().day >= self.date_of_birth.day and age >= 18 + else: + return age - 1 >= 18 + +imran = Person("Imran", date(2002, 9, 21), "Ubuntu") +print(imran) +print("Is adult?", imran.is_adult()) \ No newline at end of file diff --git a/prep-sprint5/enums.py b/prep-sprint5/enums.py new file mode 100644 index 00000000..a288483e --- /dev/null +++ b/prep-sprint5/enums.py @@ -0,0 +1,108 @@ +''' +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 +from enum import Enum +from typing import List + +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 + + +def find_possible_laptops(laptops: List[Laptop], person: Person) -> List[Laptop]: + possible_laptops = [] + for laptop in laptops: + if laptop.operating_system == person.preferred_operating_system: + possible_laptops.append(laptop) + return possible_laptops + + +people = [ + Person(name="Imran", age=22, preferred_operating_system=OperatingSystem.UBUNTU), + Person(name="Eliza", age=34, preferred_operating_system=OperatingSystem.ARCH), +] + +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="Dell", model="XPS", screen_size_in_inches=15, operating_system=OperatingSystem.UBUNTU), + Laptop(id=4, manufacturer="Apple", model="macBook", screen_size_in_inches=13, operating_system=OperatingSystem.MACOS), +] + +print("Library laptops:") # 1. list of laptops +for laptop in laptops: + print(f"- ID:{laptop.id} {laptop.operating_system.value} - {laptop.manufacturer} {laptop.model} Size: {laptop.screen_size_in_inches}") + +# receiving values from input to create person: +name = input("Enter your name: ") +age = int(input("Enter your age: ")) + +print("Choose preferred operating system:") +print("1. macOS") +print("2. Arch Linux") +print("3. Ubuntu") +choice = input(">> ") + +os_map = { + "1": OperatingSystem.MACOS, + "2": OperatingSystem.ARCH, + "3": OperatingSystem.UBUNTU, +} + +preferred_os = os_map.get(choice) + +person = Person(name=name, age=age, preferred_operating_system=preferred_os) + +print("Created person:", person) +# counts how many laptops there are with that OS +matches_count = sum( + 1 for laptop in laptops + if laptop.operating_system == person.preferred_operating_system +) +print(f"There are {matches_count} laptop(s) with {person.preferred_operating_system.value}.") + +count_laptops_by_os = { + os_type: sum(1 for laptop in laptops if laptop.operating_system == os_type) + for os_type in OperatingSystem +} + +best_os = max(count_laptops_by_os, key = count_laptops_by_os.get) +best_os_count = count_laptops_by_os[best_os] + +if best_os != person.preferred_operating_system: + print( + f"There are more laptops available with {best_os.value} " + f"({best_os_count} laptops). If you're willing to use that OS, " + "you're more likely to get a laptop." + ) +else: + print("Good choice! Your preferred OS has the highest availability.") + diff --git a/prep-sprint5/generics.py b/prep-sprint5/generics.py new file mode 100644 index 00000000..c5fc7a94 --- /dev/null +++ b/prep-sprint5/generics.py @@ -0,0 +1,21 @@ +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=20, children=[]) +aisha = Person(name="Aisha", age=30, children=[]) + +imran = Person(name="Imran", age=50, children=[fatma, aisha]) +maria = Person(name="maria", age=38,children=[fatma]) + +def print_family_tree(person: Person) -> None: + print(person.name) + for child in person.children: + print(f"- {child.name} ({child.age})") + +print_family_tree(maria) \ No newline at end of file diff --git a/prep-sprint5/inheritance.py b/prep-sprint5/inheritance.py new file mode 100644 index 00000000..d6ebb623 --- /dev/null +++ b/prep-sprint5/inheritance.py @@ -0,0 +1,47 @@ +''' +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()) + +# PREDICTION: +# Printing from person1 (Child) will work fine, as the Child class inherits from the Parent class and has access to its own methods. +# Printing from person2 (Parent) will get error because the Parent class does not have the methods get_full_name and change_last_name defined in the Child class. diff --git a/prep-sprint5/methods-person.py b/prep-sprint5/methods-person.py new file mode 100644 index 00000000..7a49086e --- /dev/null +++ b/prep-sprint5/methods-person.py @@ -0,0 +1,24 @@ + +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_year = date.today().year + birth_year = self.date_of_birth.year + age = today_year - birth_year + + if date.today().month > self.date_of_birth.month: + return age >= 18 + elif date.today().month == self.date_of_birth.month: + return date.today().day >= self.date_of_birth.day and age >= 18 + else: + return age - 1 >= 18 + + +imran = Person("Imran", date(2007,1,19), "Ubuntu") +print(imran.is_adult()) \ No newline at end of file diff --git a/prep-sprint5/mypy-checking.py b/prep-sprint5/mypy-checking.py new file mode 100644 index 00000000..fdf82373 --- /dev/null +++ b/prep-sprint5/mypy-checking.py @@ -0,0 +1,30 @@ +def open_account(balances:dict, name:str, amount:int) -> None: + balances[name] = amount + +def sum_balances(accounts) -> 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", int(9.13 * 100)) +open_account(balances,"Olya", int(7.13 * 100)) + +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 diff --git a/prep-sprint5/type-guided-refactoring.py b/prep-sprint5/type-guided-refactoring.py new file mode 100644 index 00000000..1f47b6f3 --- /dev/null +++ b/prep-sprint5/type-guided-refactoring.py @@ -0,0 +1,52 @@ +'''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.''' + +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}: ") + for each in possible_laptops: + print(f" - ID:{each.id} {each.manufacturer} {each.model} ({each.operating_system})") + print()