diff --git a/.gitignore b/.gitignore index c4234ab74..142a3706f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules -testoutput.txt +.venv/ +__pycache__/ diff --git a/prep-exercise/.gitignore b/prep-exercise/.gitignore new file mode 100644 index 000000000..0cafc1cde --- /dev/null +++ b/prep-exercise/.gitignore @@ -0,0 +1 @@ +.venv/ \ No newline at end of file diff --git a/prep-exercise/account.py b/prep-exercise/account.py new file mode 100644 index 000000000..a9518e30a --- /dev/null +++ b/prep-exercise/account.py @@ -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: dict[str, int] = { + "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}") \ No newline at end of file diff --git a/prep-exercise/inheritance.py b/prep-exercise/inheritance.py new file mode 100644 index 000000000..be6f5ca65 --- /dev/null +++ b/prep-exercise/inheritance.py @@ -0,0 +1,41 @@ +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()) + +# person2 is a Parent. Parent only defines get_name(). +# It does not define get_full_name() or change_last_name(), +# so calling those methods causes an AttributeError. \ No newline at end of file diff --git a/prep-exercise/laptop-library.py b/prep-exercise/laptop-library.py new file mode 100644 index 000000000..f3b89b476 --- /dev/null +++ b/prep-exercise/laptop-library.py @@ -0,0 +1,111 @@ +from dataclasses import dataclass +from enum import Enum +from typing import List +import sys + + +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 + + +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,), +] + +name = input("Name: ") +age_input = input("Age: ") +os_input = input("Preferred operating system: ") + +try: + age = int(age_input) +except ValueError: + print("Age must be a number", file=sys.stderr) + sys.exit(1) + +try: + preferred_os = OperatingSystem(os_input) +except ValueError: + print( + "Operating system must be one of: macOS, Arch Linux, Ubuntu", + file=sys.stderr, + ) + sys.exit(1) + +person = Person( + name=name, + age=age, + preferred_operating_system=preferred_os, +) + +possible_laptops = find_possible_laptops(laptops, person) + +print( + f"we have {len(possible_laptops)} laptop(s) with " + f"{person.preferred_operating_system.value}." +) + +ubuntu_count = 0 +arch_count = 0 +macos_count = 0 + + +for laptop in laptops: + if laptop.operating_system == OperatingSystem.UBUNTU: + ubuntu_count += 1 + elif laptop.operating_system == OperatingSystem.ARCH: + arch_count += 1 + elif laptop.operating_system == OperatingSystem.MACOS: + macos_count += 1 + + +preferred_count = len(possible_laptops) + +best_os = OperatingSystem.UBUNTU +best_count = ubuntu_count + +if arch_count > best_count: + best_os = OperatingSystem.ARCH + best_count = arch_count + +if macos_count > best_count: + best_os = OperatingSystem.MACOS + best_count = macos_count + + +if best_count > preferred_count: + print( + f"If you're willing to accept {best_os.value}, " + f"you're more likely to get a laptop because " + f"we have {best_count} available." + ) + + \ No newline at end of file diff --git a/prep-exercise/mypy.py b/prep-exercise/mypy.py new file mode 100644 index 000000000..fee5aae62 --- /dev/null +++ b/prep-exercise/mypy.py @@ -0,0 +1,11 @@ +def double(number): + return number * 3 + +print(double(10)) + + +# when checked with mypy --strict it pointed to two errors +# first missing annotation on line 1 +# secondly in line 4 call to untyped function in typed context. +# but it did not notice that in we are putting *3 +# so mypy is good for helping us to check the types. \ No newline at end of file diff --git a/prep-exercise/persone-dataclass.py b/prep-exercise/persone-dataclass.py new file mode 100644 index 000000000..bdff3dbc1 --- /dev/null +++ b/prep-exercise/persone-dataclass.py @@ -0,0 +1,14 @@ +from dataclasses import dataclass +from datetime import date + +@dataclass(frozen=True) +class Person: + name: str + date_of_birth: date + preferred_operating_system: str + +imran = Person("Imran", date(2004, 4, 15), "Ubuntu") # We can call this constructor - @dataclass generated it for us. +print(imran) + +imran2 = Person("Imran", date(2004, 4, 15), "Ubuntu") +print(imran == imran2) # Prints True \ No newline at end of file diff --git a/prep-exercise/persone-date.py b/prep-exercise/persone-date.py new file mode 100644 index 000000000..4142751a3 --- /dev/null +++ b/prep-exercise/persone-date.py @@ -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): + today = date.today() + age = today.year - self.date_of_birth.year + + if (today.month, today.day) < (self.date_of_birth.month, self.date_of_birth.day): + age -= 1 + + return age >= 18 + +imran = Person("Imran", date(2004, 4, 15), "Ubuntu") +print(imran.is_adult()) \ No newline at end of file diff --git a/prep-exercise/persone-enums.py b/prep-exercise/persone-enums.py new file mode 100644 index 000000000..e33930ac6 --- /dev/null +++ b/prep-exercise/persone-enums.py @@ -0,0 +1,48 @@ +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), +] + +for person in people: + possible_laptops = find_possible_laptops(laptops, person) + print(f"Possible laptops for {person.name}: {possible_laptops}") \ No newline at end of file diff --git a/prep-exercise/persone-generics.py b/prep-exercise/persone-generics.py new file mode 100644 index 000000000..7fdb2e0d0 --- /dev/null +++ b/prep-exercise/persone-generics.py @@ -0,0 +1,20 @@ +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=5, children=[]) +aisha = Person(name="Aisha", age=8, 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) \ No newline at end of file diff --git a/prep-exercise/persone-type-guided-ref.py b/prep-exercise/persone-type-guided-ref.py new file mode 100644 index 000000000..380da5d15 --- /dev/null +++ b/prep-exercise/persone-type-guided-ref.py @@ -0,0 +1,42 @@ +from dataclasses import dataclass +from typing import List + +@dataclass(frozen=True) +class Person: + name: str + age: int + preferred_operating_system: List[str] + + +@dataclass(frozen=True) +class Laptop: + id: int + manufacturer: str + model: str + screen_size_in_inches: float + operating_system: List[str] + + +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=["Ubuntu"]), + Person(name="Eliza", age=34, preferred_operating_system=["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}") \ No newline at end of file diff --git a/prep-exercise/persone.py b/prep-exercise/persone.py new file mode 100644 index 000000000..c46c43cb3 --- /dev/null +++ b/prep-exercise/persone.py @@ -0,0 +1,25 @@ +class Person: + def __init__(self, name: str, age: int, address:str, preferred_operating_system: str): + self.name = name + self.age = age + self.address = address + self.preferred_operating_system = preferred_operating_system + +imran = Person("Imran", 22, "London", "Ubuntu") +print(imran.name) +print(imran.address) # person.py error: "Person" has no attribute "address" [attr-defined] + +eliza = Person("Eliza", 34, "London", "Arch Linux") +print(eliza.name) +print(eliza.address) # person.py error: "Person" has no attribute "address" [attr-defined] + +def is_adult(person: Person) -> bool: + return person.age >= 18 + +print(is_adult(imran)) + + +# Because there is no address attribute in the Person class +# mypy does not accept line 9 and line 13 +# so we have to add self.address = address and define the type on def. +# then I add the address to person details. \ No newline at end of file diff --git a/prep-exercise/type.py b/prep-exercise/type.py new file mode 100644 index 000000000..c95cc40f1 --- /dev/null +++ b/prep-exercise/type.py @@ -0,0 +1,29 @@ +def half(value): + return value / 2 + +def double(value): + return value * 2 + +def second(value): + return value[1] + +print(half(22)) +print(half("hello")) +print(half("22")) + +print(double(22)) +print(double("hello")) +print(double("22")) + +print(second(22)) +print(second(0x16)) +print(second("hello")) +print(second("22")) + + +# First bug is half("hello"), +# python tries to /2 but division only works on numbers. +# second bug double("hello") again same issue, python tries to double it "hellohello" +# but it might be unintended behavior. +# third bug second(22) as it expects indexable value(str or list) +# so it is going to crash at runtime. \ No newline at end of file