hkus10
hkus10

Reputation: 463

A Simple Clock Class in python

Class Clock:   
    def __init__(self):
        self._hours = 12
        self._minutes = 0
        self._seconds = 0

    def getHours(self):
        return self._hours

    def getMinutes(self):
        return self._minutes

    def getSeconds(self):
        return self._seconds

    def show(self):
        print "%d:%02d:%02d" % (self._hours, self._minutes, self._seconds)

I want to add a method to this class called setTime which takes hours, minutes, and seconds as parameters and make appropriate changes to the object’s attributes. The following code makes use of this class and the method setTime.

clk = Clock()
clk.setTime(12, 34, 2)
print clk.getHours()
clk.show()

    def setTime(self, hours = 12, minutes = 34, seconds = 2):
        self._hours = hours
        self._minutes = minutes
        self._seconds = seconds

My question is whether my setTime method is correct? Also, how to check whether my function is correct or not?

Upvotes: 0

Views: 10598

Answers (4)

Hugh Bothwell
Hugh Bothwell

Reputation: 56654

class Clock(object):
    def __init__(self, hour=12, minute=0, second=0, milTime=False):
        super(Clock,self).__init__()
        self.hour    = hour
        self.minute  = minute
        self.second  = second
        self.milTime = milTime  # 24-hour clock?

    @property
    def hour(self):
        return self._hour if self.milTime else ((self._hour-1) % 12)+1

    @hour.setter
    def hour(self, hour):
        self._hour = hour % 24

    @property
    def minute(self):
        return self._minute

    @minute.setter        
    def minute(self, minute):
        self._minute = minute % 60

    @property
    def second(self):
        return self._second

    @second.setter
    def second(self, second):
        self._second = second % 60

    @property
    def time(self):
        return self.hour, self.minute, self.second

    @time.setter
    def time(self, t):
        self.hour, self.minute, self.second = t

    def __str__(self):
        if self.milTime:
            return "{hr:02}:{min:02}:{sec:02}".format(hr=self.hour, min=self.minute, sec=self.second)
        else:
            ap = ("AM", "PM")[self._hour >= 12]
            return "{hr:>2}:{min:02}:{sec:02} {ap}".format(hr=self.hour, min=self.minute, sec=self.second, ap=ap)

then

c = Clock(12, 15, 10)
print c                 # -> 12:15:10 PM
c.milTime = True
print c                 # -> 12:15:10
c.hour = 9
print c                 # -> 09:15:10
c.milTime = False
print c                 # -> 9:15:10 AM
c.time = 12,34,2
print c                 # -> 12:34:02 PM

Getters and setters (c.getX() etc) are un-Pythonic; if some translation is needed, use class property methods (as above), otherwise access the properties directly (as with Clock.milTime).

Upvotes: 1

Tom Zych
Tom Zych

Reputation: 13576

It looks correct to me, except for two things. You might want to remove the default values; they seem unnecessary. You want to range check the values and raise ValueError if they're out of range.

A simple test would be to set the clock to something, then get the data back and check it; repeat for a few values. This can be automated; the doctest module is fairly simple to use.

EDIT:

Here's an example of using doctest. The tests go directly into docstrings anywhere in the module. doctest.testmod() looks for them and tries to run them as if they were interactive sessions. If the output isn't as expected, it says so. If all goes well, there's no output.

class Clock:
    """Clock

    Class that acts like a clock.

    For doctest -

    >>> c = Clock()
    >>> c.setTime(23, 59, 59)
    >>> c.show()
    23:59:59
    >>> c.getMinutes()
    59
    >>> c.setTime(0, 0, 0)
    >>> c.show()
    0:00:00

    # No range or type checking yet
    >>> c.setTime(42, 'foo', [1, 2, 3])

    # However, the print will fail
    >>> c.show()
    Traceback (most recent call last):
    ...
    TypeError: int argument required

    # Another kind of error
    >>> c.setTime(foo=42)
    Traceback (most recent call last):
    ...
    TypeError: setTime() got an unexpected keyword argument 'foo'

    """

    def __init__(self):
        self._hours = 12
        self._minutes = 0
        self._seconds = 0

    def getHours(self):
        return self._hours

    def getMinutes(self):
        return self._minutes

    def getSeconds(self):
        return self._seconds

    def show(self):
        print "%d:%02d:%02d" % (self._hours, self._minutes, self._seconds)

    def setTime(self, hours = 12, minutes = 34, seconds = 2):
        self._hours = hours
        self._minutes = minutes
        self._seconds = seconds

if __name__ == '__main__':
    import doctest
    doctest.testmod()

Upvotes: 3

Cameron
Cameron

Reputation: 98776

Your setTime method is correct, however it seems odd to be setting the default hours, minutes, and seconds to such arbitrary numbers. Perhaps hours = 12, minutes = 0, and seconds = 0 would make more sense? Perhaps even doing away with the default values altogether is best.

You don't have any validation -- what if someone uses your class and accidentally sets the hours to 29?

Finally, as I mentioned in my comment, you can test your function by trying it out. Does it do the right thing in the simple case? Does it do the right thing with default values? What happens if you toss in negative seconds? What do you want to happen? These are all things you should consider when testing a method or class -- does it work in the intended case, and does it work in all the exceptional/corner cases.

For your example, you could write a simple unit test like this, using asserts:

def testSetTime():
    clock = Clock()
    clock.setTime(2, 18, 36)
    assert clock.getHours() == 2
    assert clock.getMinutes() == 18
    assert clock.getSeconds() == 36

Then you can add more tests as needed (note that each unit test should test only one thing).

Upvotes: 1

ceth
ceth

Reputation: 45295

You can initialize the time in the class constructor:

Class Clock:   
    def __init__(self, hours, minutes, seconds):
        self._hours = hours
        self._minutes = minutes
        self._seconds = seconds
....


clk = Clock(12, 34, 2)

Upvotes: 4

Related Questions