Nite
Nite

Reputation: 268

Validating data (mutators) in a class

I'm trying to reject data (convert to 0) if for example hour is greater than 23, minute is greater than 60 and second is greater than 60, however I'm having issues where it does not do anything. I'm not sure if I'm just not initializing my get/set methods correctly or what.

Here is my code:

class Clock(object):

    def __init__(self, hour, minute, second):
        self.__hour = hour
        self.__minute = minute
        self.__second = second

    def setHour(self, hour):
        self.__hour = hour
        if self.__hour > 23:
            self.__hour = 0

    def getHour(self):
        return self.__hour

    def setMinute(self, minute):
        self.__minute = minute
        if self.__minute > 60:
            self.__minute = 0

    def getMinute(self):
        return self.__minute

    def setSecond(self, second):
        self.__second = second
        if self.__second > 60:
            self.__second = 0

    def getSecond(self):
        return self.__second

    def __str__(self):
        if self.__hour > 11:
            return 'The Time is {}:{}:{} PM'.format(self.__hour, self.__minute, self.__second)
        else:
            return 'The Time is {}:{}:{} AM'.format(self.__hour, self.__minute, self.__second)


stopwatch = Clock(0, 0, 0)
print(stopwatch)
watch = Clock(10, 30, 0)
print(watch)
wallclock = Clock(5, 66, 42)
print(wallclock)

Upvotes: 0

Views: 308

Answers (3)

Tim
Tim

Reputation: 2637

If you are using Python 3 a much nicer solution is to use properties (simplified to only hours), eg:

class Clock:
    def __init__(self, hour, minute, second):
        self._hour = self._minute = self._second = None

        # Call the properties to apply validation rules
        self.hour = hour
        self.minute = minute
        self.second = second

    def __str__(self):
        return 'The Time is {:02}:{:02}:{:02}'.format(self._hour, self._minute, self.second)

    @property
    def hour(self):
        return self._hour

    @hour.setter
    def hour(self, value):
        self._hour = 0 if value > 23 else value

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

    @minute.setter
    def minute(self, value):
        self._minute = 0 if value > 59 else value

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

    @second.setter
    def second(self, value):
        self._second = 0 if value > 59 else value

PS your code allows for 61 seconds and minutes ;)

Upvotes: 0

nick
nick

Reputation: 853

Yes, you haven't call your methods in your init function.
I have another way to implement your thought, just add a __setattr__ function in your class:

def __setattr__(self, name, value):
    if name in ['__minute', '__second'] and value > 60:
        return None
    if name in ['__hour'] and value > 23:
        return None
    super().__setattr__(name, value)

This function will check if the value is correct, and convert the value to 0 if the value is out of boundary.This is a pythonic function.

Upvotes: 0

Nick Weseman
Nick Weseman

Reputation: 1532

You don't check if the hours/minutes/seconds are out of bounds in __init__. Update your __init__ to:

def __init__(self, hour, minute, second):
    self.__hour = hour
    if self.__hour > 23:
        self.__hour = 0

    self.__minute = minute
    if self.__minute > 60:
        self.__minute = 0

    self.__second = second
    if self.__second > 60:
        self.__second = 0

or better yet (to follow DRY - Don't Repeat Yourself):

def __init__(self, hour, minute, second):
    self.setHour(hour)
    self.setMinute(minute)
    self.setSecond(second)

As @brenbarn mentions, you can also call the setHour, setMinute, and setSecond methods at the bottom to test that they also work:

stopwatch = Clock(0, 0, 0)
stopwatch.setHour(30)
print(stopwatch)
watch = Clock(10, 30, 0)
watch.setMinute(69)
print(watch)
wallclock = Clock(5, 66, 42)
wallclock.setSecond(70)
print(wallclock)

Upvotes: 1

Related Questions