The client code can access an attribute using date ...
dot notation, and the name of the attribute
>>> date.year
2015
We can also use this notation to access a method
>>> date.format_date()
'October 3, 2015'
Inside a class, the variable that points to the object is
self
We use dot notation with self to call a method
self.get_month_name()
Or use an attribute
self.year
The Time Class
Let's create another class, Time
The constructor takes a time string using the format
HH:MM:SS
HH is the hours on a 24 hour clock with values from 0
to 23
MM is a two digit minute and SS is a two digit second
Their values range from 0 to 59
Here is the Time constructor
# expects a string of the form HH:MM:SS
# where hours are expressed in numbers from 0 to 23
def __init__(self, time_string):
self.hours, self.minutes, self.seconds = time_string.split(":")
self.hours = int(self.hours)
self.minutes = int(self.minutes)
self.seconds = int(self.seconds)
Let's also create the format_time method
This method will give us a nicely formated string representing the time
# returns a string in the form HH:MM:SS AM/PM
def format_time(self):
hours = self.hours
am_pm = "AM"
if hours > 12:
hours -= 12
am_pm = "PM"
return str(hours) + ":" + str(self.minutes) + ":" + str(self.seconds) + " " + am_pm
The variables hours and
am_pm are local variables ...
Exceptions allow a program to respond gracefully ...
when unexpected things happen
There are specific Python exceptions for different kinds of problems
Here we need to raise a TypeError like this
if not isinstance(time_string, str):
raise TypeError("Time constructor expects a string argument")
Now if we call the constructor and time_string
is not a string
We get the following
>>> t1 = Time(55)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/glenn/workspace-mars/it117/resources_it117/code_it117/example_code_it117/10_chapter_example_code/time_3.py", line 13, in __init__
raise TypeError('Time constructor expects a string argument')
TypeError: Time constructor expects a string argument
Next, we need to be sure that time_string has the
right format
It must have two digits followed by a colon, : ...
followed by two more digits and another colon ...
then two more digits
I don't want the constructor to get too large
Because then it would be hard to read
So I am going to place the code to check the format ...
in a separate method called has_valid_format
Here is the code
# returns true if the string has the form HH:MM:SS
def has_valid_format(s):
pattern = re.compile("\d\d:\d\d:\d\d")
match = pattern.match(s)
return match
Here we use regular expressions to try to match the string ...
and return a pointer to the match object
If the format is good, this variable will point to a real object ...
and the calling statement will interpret this as True
If the string does not have right format ...
the value of match will be None
None is interpreted as False in an if statement
We also need to make sure that the hours value is between 0 and 23 ...
and the minutes and seconds are between 0 and 59
To do this I am going to create a new method
time_numbers_in_range
# returns true if the numbers for hours, minutes and seconds
# are within the proper range
def time_numbers_in_range(hours, minutes, seconds ):
if not 0 <= hours <= 23:
return False
if not 0 <= minutes <= 59:
return False
if not 0 <= seconds <= 59:
return False
return True
Of course, we have to change the constructor to use these new methods
# expects a string of the form HH:MM:SS
# where hours are expressed in numbers from 0 to 23
def __init__(self, time_string):
if not isinstance(time_string, str):
raise TypeError("Time constructor expects a string argument")
if not self.has_valid_format(time_string):
raise ValueError("String must have the format HH:MM:SS")
hours, minutes, seconds = time_string.split(":")
hours = int(hours)
minutes = int(minutes)
seconds = int(seconds )
if not self.time_numbers_in_range(hours, minutes, seconds ):
raise ValueError("One of the time values is not in the proper range")
self.__seconds = hours * 60 * 60 + minutes * 60 + seconds
Hiding Methods
An attribute is invisible outside the class ...
if it's name begins with two underscores, __
This also works for methods
In the example above we created two methods
has_valid_format
time_numbers_in_range
These methods are only used by the constructor
They are not intended for use outside the class
So we should hide them by adding __ ...
to the beginning of their names
Most methods in a class will be used by the client code
But any method not needed by the client code ...
should be hidden
A class should be a black box
It should have specified inputs and outputs
Users of the class do not need to know how it works