Prototyping versus planning
Related code
class Time: """Represents the time of day. attributes: hour, minute, second """ def set(self, hour, minute, second): self.hour = hour self.minute = minute self.second = second def print(self): print(f"{self.hour:02}:{self.minute:02}:{self.second:02}") def add(self, other): sum = Time() sum.hour = self.hour + other.hour sum.minute = self.minute + other.minute sum.second = self.second + other.second if sum.second >= 60: sum.second -= 60 sum.minute += 1 if sum.minute >= 60: sum.minute -= 60 sum.hour += 1 return sum def increment(self, seconds): self.second += seconds while self.second >= 60: self.second -= 60 self.minute += 1 while self.minute >= 60: self.minute -= 60 self.hour += 1 start = Time() start.set(9, 45, 0) duration = Time() duration.set(2, 30, 0)
divmod
divmod is a built-in function that takes two arguments and returns a pair of values representing the quotient and remainder of the division operation. The syntax is:
divmod(a, b)
Here, a is the numerator, and b is the denominator. The function returns a tuple (q, r) where q is the quotient (the result of the integer division) and r is the remainder.
>>> divmod(10, 3) (3, 1)
In this example, divmod(10, 3) calculates the quotient and remainder of dividing 10 by 3. The result is a tuple (3, 1), where 3 is the quotient and 1 is the remainder.
So, divmod is same as floor division and modulus combined.
>>> divmod(10, 3) == (10 // 3, 10 % 3) True
Prototyping versus planning
The development plan I am demonstrating is called "prototype and patch". For each method, I wrote a prototype that performed the basic calculation and then tested it, patching errors along the way.
This approach can be effective, especially if you don't yet have a deep understanding of the problem. But incremental corrections can generate code that is unnecessarily complicated, since it deals with many special cases, and unreliable, since it is hard to know if you have found all the errors.
An alternative is designed development, in which high-level insight into the problem can make the programming much easier.
For example, we can convert Time objects to integers and take advantage of the fact that the computer knows how to do integer arithmetic.
Here is a method that converts time to integer:
class Time: ... def to_seconds(self): minutes = self.hour * 60 + self.minute seconds = minutes * 60 + self.second return seconds ...
And here is a function that converts integer to a Time:
def seconds_to_time(seconds): time = Time() minutes, time.second = divmod(seconds, 60) time.hour, time.minute = divmod(minutes, 60) return time
Since seconds_to_time
takes an integer (seconds), and not Time
instance,
it is not reasonable to be part of the Time
class. So we define it as a function.
Once you are convinced they are correct, you can use them to rewrite add
and increment
:
class Time: ... def add(self, other): seconds = self.to_seconds() + other.to_seconds() return seconds_to_time(seconds) def increment(self, seconds): seconds += self.to_int() return seconds_to_time(seconds) ...
Exercises
Rewrite increment using time_to_int and int_to_time.