python 3.6 Background Classes allow us to define new types for Python. We can fi
ID: 3857557 • Letter: P
Question
python 3.6
Background Classes allow us to define new types for Python. We can first think of a class as defining a new container - instead of a list, tuple, set, or dictionary, we can have our own collection of values, each with a chosen name. We can then read out a value or update a value, much like reading or replacing the values in a list or dictionary. But we can also put methods in a class definition, giving us a way to specify the exact ways we should interact with values of this new type. Once we have created a class definition, we can create as many objects of the new type as we want and use them in our programs. We can create entirely new types during the design phase of writing a program. This enables us to think in terms of types (and instances of types) that better model what we see in the real world, instead of endlessly relying on lists or dictionaries (and having to remember exactly how we intended to use those things as proxies for the values we actually had in mind) Exceptions allow us to recover from unusual events - some unavoidable (user types in bad file name or bad input in general), some unexpected (such as IndexErrors when stepping through a list). Without exceptions, we tend to program in an "ask permission, then attempt" style of calculation. But using exceptions, we can instead program iin a "try it first, beg for forgiveness" approach by writing code that specifies how to recover from exceptions that we allowed to occurExplanation / Answer
Event.py
---------------------------
from TimeSpan import *
from Moment import *
class Event:
def __init__(self, title, location, timespan):
"""
Constructor
:param title:
:param location:
:param timespan:
:return:
"""
self.title = title
self.location = location
self.timespan = timespan
def __str__(self):
return "Event: {0}. Location: {1}. {2}, {3} ".format(self.title, self.location, self.timespan.start, self.timespan.stop)
def __repr__(self):
return "Event ("{0}", "{1}", {2})".format(self.title, self.location, repr(self.timespan))
if __name__ == '__main__':
start = Moment(2014, 12, 4, 14, 1)
stop = Moment(2014, 12, 4, 14, 30)
span = TimeSpan(start, stop)
e = Event("Lunch With Mum", "Home", span)
print(e)
print(repr(e))
-----------------------------------------------------------------
EventPlanner.py
-------------------------------
from ScheduleConflictError import *
class EventPlanner:
def __init__(self, owner, events=None):
"""
Constructor
:param owner:
:param events:
:return:
"""
self.owner = owner
if events is None:
self.events = []
else:
self.events = events
def __str__(self):
return "EventPlanner ("{0}", {1})".format(self.owner, self.events)
def __repr__(self):
return str(self)
def add_event(self, event):
"""
Add the given event
:param event:
:return:
"""
# check whether there is any events so the list
if len(self.events) == 0:
self.events.append(event)
return None
else:
for ev in self.events:
if ev.timespan.overlaps(event.timespan):
raise ScheduleConflictError("The event {0}, overlaps with event {1}".format(event, ev))
# if we get here then that means there is no overlap so we add the event
self.events.append(event)
return None
def add_events(self, events):
"""
Adds events in the given list
:param events:
:return:
"""
events_not_added = 0
length = len(events)
if length == 0:
return 0
else:
for i in range(0, length):
ev = events.pop()
try:
self.add_event(ev)
except ScheduleConflictError as ex:
events_not_added += 1
return events_not_added
def available_at(self, moment):
"""
Checks if the owner is available at the given mat
:param moment:
:return:
"""
if len(self.events) == 0:
return True
else:
for ev in self.events:
if ev.timespan.during_moment(moment):
return False
return True
def available_during(self, timespan):
"""
Checks if the owner is available at the given timespan
:param timespan:
:return:
"""
if len(self.events) == 0:
return True
else:
for ev in self.events:
if ev.timespan.overlaps(timespan):
return False
return True
def can_attend(self, event):
"""
Checks if the owner can attend the event
:param event:
:return:
"""
if len(self.events) == 0:
return True
else:
# make sure the User is not available during that event
return not self.available_during(event.timespan)
----------------------------------------------------------------------------
Moment.py
--------------------------------
from TimeError import *
class Moment():
def __init__(self, year=0, month=0, day=0, hour=0, minute=0):
"""
Constructor
:param year:
:param month:
:param day:
:param hour:
:param minute:
:return:
"""
try:
if Moment.is_int("Year", year) and Moment.is_int("Month", month) and Moment.is_int("Day", day)
and Moment.is_int("Hour", hour) and Moment.is_int("Minute", minute):
if Moment.is_year_valid(year):
self.year = year
if Moment.is_month_valid(month):
self.month = month
if Moment.is_day_valid(year, month, day):
self.day = day
if Moment.is_hour_valid(hour):
self.hour = hour
if Moment.is_minute_valid(minute):
self.minute = minute
except Exception as e:
print(e)
def __str__(self):
fmonth = self.month
fday = self.day
fhour = self.hour
fminute = self.minute
if self.month < 10:
fmonth = "0{0}".format(self.month)
if self.day < 10:
fday = "0{0}".format(self.day)
if self.hour < 10:
fhour = "0{0}".format(self.hour)
if self.minute < 10:
fminute = "0{0}".format(self.minute)
return "{0}/{1}/{2}-{3}:{4}".format(self.year, fmonth, fday, fhour, fminute)
def __repr__(self):
return "Moment({0}, {1}, {2}, {3}, {4})".format(self.year, self.month, self.day, self.hour, self.minute)
def before(self, other):
"""
Checks if the Moment is before other
:param other:
:return:
"""
if self.year < other.year:
return True
else:
if self.month < other.month and self.year < other.year:
return True
else:
if self.day < other.day and (self.month < other.month and self.year < other.year):
return True
else:
if self.hour < other.hour and (self.day < other.day and self.month < other.month and self.year < other.year):
return True
else:
if self.minute < other.minute and (self.hour < other.hour and self.day < other.day and self.month < other.month and self.year < other.year):
return True
else:
return False
def equal(self, other):
"""
Checks if the two moments are equal
:param other:
:return:
"""
is_equal = False
if self.year == other.year:
is_equal = True
if self.month == other.month:
is_equal = True
if self.day == other.day:
is_equal = True
if self.hour == other.hour:
is_equal = True
if self.minute == other.minute:
is_equal = True
else:
is_equal = False
else:
is_equal = False
else:
is_equal = False
else:
is_equal = False
else:
is_equal = False
return is_equal
def after(self, other):
"""
Checks is the moment is after the other
:param other:
:return:
"""
is_early = False
if self.year > other.year:
is_early = True
else:
if self.month > other.month and self.year > other.year:
is_early = True
else:
if self.day > other.day and (self.month > other.month and self.year > other.year):
is_early = True
else:
if self.hour > other.hour and (self.day > other.day and self.month > other.month and self.year > other.year):
is_early = True
else:
if self.minute > other.minute and (self.hour > other.hour and self.day > other.day and self.month > other.month and self.year > other.year):
is_early = True
else:
is_early = False
return is_early
def delta(self, year=0, month=0, day=0, hour=0, minute=0):
"""
Transforms the current moment in a positive or negative way
:param year:
:param month:
:param day:
:param hour:
:param minute:
:return:
"""
# first check if the deal with the minutes
carry_over_hours = int((self.minute + minute) / 60)
new_minutes = (self.minute + minute) % 60
#then deal with the hours
carry_over_days = int((self.hour + hour + carry_over_hours) / 24)
new_hours = (self.hour + hour + carry_over_hours) % 24
#deal with days
remaining_days_to_end_of_the_current_month = Moment.get_number_of_days_in_a_month(self.year, self.month)- (self.day + carry_over_days)
#check if the days we have overflow
overflow_days = day - remaining_days_to_end_of_the_current_month
#if the overflow_days are 0 or negative then we good we end there else we loop through the days until they are done
new_month = 0
carry_over_months = 0
new_day = 0
new_year = 0
if overflow_days <= 0:
new_day = self.day + day + carry_over_days
new_month = self.month
carry_over_months = 0
overflow_days = 0
else:
carry_over_months += 1
new_month = self.month + 1
new_year = self.year
while overflow_days > 0:
if new_month == 13:
new_month = 1
new_year += 1
month_length = Moment.get_number_of_days_in_a_month(new_year, new_month)
overflow = overflow_days - month_length
if overflow < 0:
#here we remain in the same month
new_day = overflow_days
overflow_days = 0
elif overflow == 0:
#here we remain in the same month and set the day to the last day of the month
new_day = month_length
overflow_days = 0
elif overflow > 0:
carry_over_months += 1
new_month += 1
overflow_days = overflow
#now we deal with the months
carry_over_years = 0
if (self.month + month + carry_over_months) % 12 == 0:
new_month = 12
else:
new_month = (self.month + month + carry_over_months) % 12
carry_over_years = int((self.month + month + carry_over_months) / 12)
# dealing with years
new_year = self.year + carry_over_years + year
#bringing everything together
self.year = round(new_year)
self.month = round(new_month)
self.day = round(new_day)
self.hour = round(new_hours)
self.minute = round(new_minutes)
def is_leap_year(year):
"""
Checks if the year is leap year
:param year:
:return: Boolean either true or false
"""
if year % 400 == 0:
return True
elif year % 100 == 0:
return False
elif year % 4 == 0:
return True
else:
return False
def is_int(name, value):
"""
Checks if the value provided is int
:param name:
:param value:
:return:
"""
if isinstance(value, int):
return True
else:
raise TimeError("The value provided for %s is not an integer" % name)
def is_year_valid(year):
if year >= 0:
return True
else:
raise TimeError("The value {0} provided for year is not valid".format(year))
def is_month_valid(month):
"""
Checks if the month is valid
:param month:
:return:
"""
if month >= 1 and month <= 12:
return True
else:
raise TimeError("The value {0} provided for month is not valid".format(month))
def is_day_valid(year, month, day):
"""
Checks if the day passed is valid
:param year:
:param month:
:param day:
:return:
"""
start_day = 1
last_day = 0
#first we determine the last day of the month
if month == 1 or month == 3 or month == 5 or month == 7 or month == 8 or month == 10 or month == 12:
last_day = 31
elif month == 4 or month == 6 or month == 9 or month == 11:
last_day = 30
else:
if Moment.is_leap_year(year):
last_day = 29
else:
last_day = 28
#then we check if they day of the month is valid
if day >= start_day and day <= last_day:
return True
else:
raise TimeError("The value {0} for day of {1} month and {2} year is not valid".format(
day, month, year))
def is_hour_valid(hour):
if hour >=0 and hour <=23:
return True
else:
raise TimeError("The value {0} provided for hour is not valid".format(hour))
def is_minute_valid(minute):
if minute >= 0 and minute <= 59:
return True
else:
raise TimeError("The value {0} provided for minute is not valid".format(minute))
def get_number_of_days_in_a_month(year, month):
days_in_a_month = 0
if month == 1 or month == 3 or month == 5 or month == 7 or month == 8 or month == 10 or month == 12:
days_in_a_month = 31
elif month == 4 or month == 6 or month == 9 or month == 11:
days_in_a_month = 30
else:
if Moment.is_leap_year(year):
days_in_a_month = 29
else:
days_in_a_month = 28
return days_in_a_month
--------------------------------------------------------------------
ScheduleConflictError(Exception).py
---------------------------------
class ScheduleConflictError(Exception):
def __init__(self, msg):
self.msg = msg
def __str__(self):
return self.msg
def __repr__(self):
return self.msg
--------------------------------------------------------------------
TimeError.py
--------------------------------
class TimeError(Exception):
def __init__(self, msg):
self.msg = msg
def __str__(self):
return self.msg
def __repr__(self):
return self.msg
-------------------------------------------------------------------
TimeSpan.py
-------------------------------------
from Moment import *
from TimeError import *
class TimeSpan:
def __init__(self, start, stop):
"""
Constructor
:param start:
:param stop:
:return:
"""
if stop.before(start):
raise TimeError("The stop moment {0} cannot be before start moment {1}".format(stop, start))
else:
self.start = start
self.stop = stop
def __str__(self):
return "Timespan({0}, {1})".format(self.start, self.stop)
def __repr__(self):
return "Timespan({0}, {1})".format(repr(self.start), repr(self.stop))
def during_moment(self, moment):
"""
Checks if the moment is during the timespan
:param moment:
:return:
"""
if self.start.before(moment) and self.stop.after(moment):
return True
elif self.start.equal(moment) or self.stop.equal(moment):
return True
else:
return False
def overlaps(self, other):
"""
Checks if the Time spans overlaps
:param other:
:return:
"""
if self.start.equal(other.start) or self.stop.equal(other.stop):
return True
elif self.start.before(other.start) and self.stop.after(other.start):
return True
elif other.stop.after(self.start) and other.stop.before(self.stop):
return True
else:
return False
def set_duration(self, year=0, month=0, day=0, hour=0, minute=0):
"""
Resets ths values of the stop moment
:param year:
:param month:
:param day:
:param hour:
:param minute:
:return:
"""
self.stop.delta(year, month, day, hour, minute)
if self.stop.before(self.start):
raise TimeError("The stop Moment is before the start Moment")
else:
return True
Related Questions
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.