Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file not shown.
35 changes: 35 additions & 0 deletions sprint-5-exercises/class-in-python.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
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.age)

eliza = Person("Eliza", 34, "Arch Linux")
print(eliza.name)
print(eliza.age)


def is_adult(person: Person) -> bool:
return person.age >= 18


print(is_adult(imran))


def get_address(person: Person) -> str:
return person.address
# it still gives error as Person class does not have any attribute called address.


# this is the error given by mypy:
# class-in-python.py:10: error: "Person" has no attribute "address" [attr-defined]
# class-in-python.py:14: error: "Person" has no attribute "address" [attr-defined]
# Found 2 errors in 1 file (checked 1 source file)

# Solution:
# The Person class doesn't define an address attribute, but the code tries to access it. To fix the error, either remove the address references or define address as an attribute in the constructor and provide it when creating each Person object.
19 changes: 19 additions & 0 deletions sprint-5-exercises/data-class.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
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):
today = date.today()
age = today.year - self.date_of_birth.year

return age >= 18


imran = Person("Imran", date(2004, 10, 10), "Ubuntu")
print(imran.is_adult())
158 changes: 158 additions & 0 deletions sprint-5-exercises/enumm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
from enum import Enum
from dataclasses import dataclass
import sys


# Enum gives us a fixed set of operating system choices.
class OperatingSystem(Enum):
MACOS = "macOS"
ARCH = "Arch Linux"
UBUNTU = "Ubuntu"


# Dataclass automatically creates the __init__ method for us.
@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


# The laptops already available in the library.
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,
),
]


# Get the user's name.
name = input("What is your name? ")


# Convert the age from a string to an integer.
# If conversion fails, print the error to stderr and exit with code 1.
try:
age = int(input("What is your age? "))
except ValueError:
print("Invalid age.", file=sys.stderr)
sys.exit(1)


# Convert the user's input into an OperatingSystem enum value.
# If the value isn't one of our enum choices, exit with an error.
try:
preferred_operating_system = OperatingSystem(
input("What is your preferred operating system? ")
)
except ValueError:
print("Invalid operating system.", file=sys.stderr)
sys.exit(1)


# Create a Person using the validated input.
person = Person(
name=name,
age=age,
preferred_operating_system=preferred_operating_system,
)


# Count laptops matching the person's preferred operating system.
count = 0

for laptop in laptops:
if laptop.operating_system == person.preferred_operating_system:
count += 1


print(
f"There are {count} laptops available with "
f"{person.preferred_operating_system.value}."
)


# Count how many laptops are available for each operating system.
available_laptops = {}

for laptop in laptops:
os = laptop.operating_system

if os not in available_laptops:
available_laptops[os] = 0

available_laptops[os] += 1


# Find the operating system with the most available laptops.
most_available_os = max(
available_laptops,
key=available_laptops.__getitem__,
)


# If another operating system has more laptops, recommend it.
if most_available_os != person.preferred_operating_system:
print(
f"You are more likely to get a laptop if you accept "
f"{most_available_os.value}."
)


# # LAPTOP LIBRARY PROGRAM FLOW:
#
# 1. Define OperatingSystem enum
# ↓
# 2. Define Person and Laptop dataclasses
# ↓
# 3. Create list of available laptops
# ↓
# 4. Get user's name, age, and preferred OS
# ↓
# 5. Validate and convert user input
# ↓
# 6. Create a Person object
# ↓
# 7. Count laptops matching the user's preferred OS
# ↓
# 8. Count laptops for each operating system
# ↓
# 9. Find the OS with the most laptops
# ↓
# 10. Compare it with the user's preferred OS
# ↓
# 11. Recommend another OS if more laptops are available
23 changes: 23 additions & 0 deletions sprint-5-exercises/generics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from dataclasses import dataclass


@dataclass(frozen=True)
class Person:
name: str
age: int
children: list


fatma = Person(name="Fatma", age= 22, children=[])
aisha = Person(name="Aisha", age = 15, children=[])

imran = Person(name="Imran", age = 45, 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)
72 changes: 72 additions & 0 deletions sprint-5-exercises/inheretance.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
from typing import Iterable, Optional


class ImmutableNumberList:
# We accept any `Iterable[int]` here, so can construct with a list, a set, or anything else that can be iterated.
def __init__(self, elements: Iterable[int]):
# We copy the elements so that if someone mutates the passed in elements list, our copy won't be mutated.
self.elements = [element for element in elements]

def first(self) -> Optional[int]:
if not self.elements:
return None
return self.elements[0]

def last(self) -> Optional[int]:
if not self.elements:
return None
return self.elements[-1]

def length(self) -> int:
return len(self.elements)

def largest(self) -> Optional[int]:
# To find the largest element, we need to go through the entire list (which may take some time).
if not self.elements:
return None
largest = self.elements[0]
for element in self.elements:
if element > largest:
largest = element
return largest


# A SortedImmutableNumberList is the same as an ImmutableNumberList,
# but it changes some aspects.
class SortedImmutableNumberList(ImmutableNumberList):
def __init__(self, elements: Iterable[int]):
# We do extra work here when constructing the list,
# to make sure the elements are sorted.
# This takes more time than the ImmutableNumberList version would.
super().__init__(sorted(elements))

# This method overrides (replaces) the method with the same name on the super-class.
def largest(self) -> Optional[int]:
# Because we know the elements were already sorted in the constructor,
# we can implement finding the largest number faster.
# We don't need to look through every element - we know the largest element is at the end.
# Because we did extra work one time before (in the constructor),
# we can avoid re-doing that work every time someone calls `largest()`.
return self.last()

def max_gap_between_values(self) -> Optional[int]:
if not self.elements:
return None
previous_element = None
max_gap = -1
for element in self.elements:
if previous_element is not None:
gap = element - previous_element
if gap > max_gap:
max_gap = gap
previous_element = element
return max_gap


values = SortedImmutableNumberList([1, 19, 7, 13, 4])
print(values.largest())
print(values.max_gap_between_values())

unsorted_values = ImmutableNumberList([1, 19, 7, 13, 4])
print(unsorted_values.largest())
# print(unsorted_values.max_gap_between_values())
13 changes: 13 additions & 0 deletions sprint-5-exercises/method-vs-free-function.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Advantages of methods:

They keep related code together. A method belongs to a class, so it keeps the behavior related to that object in one place.

They are easier to understand. When you see person.is_adult(), it is clear that the action is related to a Person.

They can directly access the object's data. A method can use self to access attributes of the object.

They make code more organized. Classes group the data and the operations that work with that data together.

They can make code easier to reuse. Once a class has a method, every instance of that class can use it.

Encapsulation - if we change the implementation of Person (e.g. we start storing a date of birth instead of an age), it’s more obvious what things we need to change.
18 changes: 18 additions & 0 deletions sprint-5-exercises/method.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
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

return age >= 18


imran = Person("Imran", date(2004, 10, 10), "Ubuntu")
print(imran.is_adult())
Loading
Loading