Section 3: Classes & Objects
    
     Table of Contents > 
        Chapter 5 > Section 3  
    
    The opening documentation for the random module referred to
    the Random class.  The term class and the
    associated term object are used extensively in the documentation of
    Python modules.  In this section of the course we examine what these
    terms mean.
    
    A class encapsulates data along with associated operations on that data. You
    can think of a class as a blueprint for a new type of data.  We use the
    blueprint to create instances of that data.  These instances are known
    as objects.
      
    It so happens that we've been using classes and objects throughout the
    course without mentioning them explicitly.  In fact, every piece of
    data that we have worked with is an object and is therefore an
    instance of some class.  We have noted that a class
    encapsulates data and associated operations on that data.  These
    operations are known as methods.  The str data
    type, for example, is defined by a class.  The methods for this class
    are documented in Section
      4.7.1 of the Standard Python Library.  Let's take a look at the
    documentation for the center method, for example:
    
    str.center(width[, fillchar])
      
      Return centered in a string of length width. Padding is done using
      the specified fillchar (default is a space).
      
      (http://docs.python.org/3/library/stdtypes.html#string-methods)
    
    
    At first, this might not look any different from the documentation for a
    function.  Indeed, there are many similarities.  Methods take
    parameters that are documented in the same way as those for functions, for
    example.  In this particular case, we see that the center
    method takes two parameters, one of which is optional.  There is also a
    purpose statement that defines what the method will do when it's called. 
    
    But let's take a closer look.  The opening sentence of the purpose
    statement indicates: "Return centered in a string of length width." 
    This begs the question: "What is it that is returned centered in a
    string of length width?"  Methods are called with an implicit
      parameter that specifies the object on which the operation is to be
    performed.  Consider the following code segment:
    
    >>> fname = 'Joe'
      >>> lname = 'Jiang'
      >>> fname.center(7, '*')
      
'**Joe**'
      >>> lname.center(9, '^')
      
'^^Jiang^^'
    
    
    First note that fname and lname each refer to a
    string object.  The statement fname.center(7, '*')
    will, according to the documentation, 
    
      Return fname centered in a string of length 7, padded with '*'s.
    
    And indeed that's what we got.  In this case, fname is
    the implicit parameter.  It specifies that the center
    method is to be applied to the object referenced by fname.
      
    Similarly, lname.center(9, '^') will return lname
    centered in a string of length 9, padded with '^'s. 
    In this case, lname is the implicit parameter.  
    We have stated that every piece of data in Python is an object -
    even ints and floats.  So, for example, the
    float class provides the following method, among others:
    
    float.is_integer()
      
      Return True if the float instance is finite with integral
      value, and False otherwise:
      
      >>> (-2.0).is_integer()
        
True
        
        >>> (3.2).is_integer()
        False
      
      New in version 2.6.
(http://docs.python.org/3/library/stdtypes.html#additional-methods-on-float)
    
    
    The datetime module
    Now let's take a look at the documentation for a class that we have not yet
    seen.  Section
      8.1.1 of the documentation for the datetime module lists
    the following classes, each of which defines a new type of data:
    
    class datetime.date
      class datetime.time
      
class datetime.datetime
      class datetime.timedelta
      
class datetime.tzinfo
    
    Let's consider the date class.  To create a date object,
    we use a special method known as a constructor that has the same
    name as the class:
    
    class datetime.date(year, month, day) 
      
      All arguments are required. Arguments may be ints or longs,
      in the following ranges: 
      
      MINYEAR <= year <= MAXYEAR 
      
      1 <= month <= 12 
      
      1 <= day <= number of days in the given month and year
      
      
      If an argument outside those ranges is given, ValueError is
      raised.
      
(http://docs.python.org/3/library/datetime.html#datetime.date)
    
    The following code segment illustrates the use of this constructor:
    
     >>> d1 = datetime.date(2012, 5, 15)
 
      >>> d2 = datetime.date(1984, 7, 11)
    
    so d1 references the date object that represents the date May
    15, 2012 while  d2 references the date object that represents
    the date July 11, 1984.  
    
    The documentation then lists a number of class methods that also
    provide a way of constructing a date.  For example, the today
    method.  A class method is a method that does not operate on a specific
    instance of the class.  However, it provides functionality that is
    related to the class.  It is invoked using the name of the class as
    illustrated below:
    
     >>> from datetime import date
      >>> dt = date.today()
      >>> print(dt)
      2012-04-10
    
    Pay particular attention to how this method was called:
    
    date.today()
    
    where date is the name of the class, not a reference to an
    instance of that class. 
    
    The Python documentation now lists class attributes.  These are
    constants that belong to the class.  For example:
    
    date.min
      
      The earliest representable date, date(MINYEAR, 1, 1)
      
(http://docs.python.org/3/library/datetime.html#datetime.date)
    
    
    Again, note that these class attributes are typically invoked using
    the name of the class.
    
    The documentation then goes on to list instance attributes. 
    Each instance of the class has its own copy of these attributes.  Here
    are some of the instance attributes associated with the date class:
    
    date.year
      
      Between MINYEAR and MAXYEAR inclusive.
      
      date.month
      
      Between 1 and 12 inclusive.
      
      date.day
      
      Between 1 and the number of days in the given month of the given year.
      (http://docs.python.org/3/library/datetime.html#datetime.date)
    
    
    On the surface, it may appear that there is no difference between date.min
    and date.year (or date.month, date.day). 
    However, date.min was listed as a class
    attribute whereas date.year, date.month and date.day
    are described as instance attributes.  Each object of type date
    will have it's own copy of each of the instance attributes.  However,
    you can think of class attributes as shared among all objects of that
    class.  
    
    Let's look at an example to illustrate the use of instance attributes:
    
     >>> from datetime import date
      >>> dt = date.today()
      >>> print(dt.year)      #print dt's year
      2012
      >>> bday = date(1990, 5, 12)
      >>> print(bday.year)    #print bday's year
      
1990
    
    We create two date objects - one represents "today's" date (on whatever date
    the code was run) and the other someone's birthday.  We see that each
    date object has a year attribute.  The value of dt.year
    is 2012 whereas the value of bday.year is 1990. 
    Similarly, each date object has its own month and day
    attributes.  
    
    As we have already noted, class attributes are typically invoked
    using the name of the class but can also been invoked using an instance of
    the class as illustrated below:
    
     >>> from datetime import date
      >>> print(date.min)    # with name of class
      
0001-01-01
      >>> dt = date.today()
      >>> print(dt.min)      # with instance of
      class
      0001-01-01
    
    The documentation then goes on to describe supported operations on date
    and  timedelta objects such as + and -. 
    
 
    Finally, the instance methods are presented.  These methods operate on
    an instance of the class.  For example,
    
    date.replace(year, month, day)
       
      Return a date with the same value, except for those parameters given new
      values by whichever keyword arguments are specified. For example, if 
      
d == date(2002, 12, 31), 
      
then 
      
d.replace(day=26) == date(2002, 12, 26).
      (http://docs.python.org/3/library/datetime.html#datetime.date)
    
    
    The distinction between class methods and instance methods is similar to the
    distinction between class attributes and instance attributes.  Class
    methods operate on class attributes only, not on an instance of the
    class.  They are typically invoked using the name of the class. 
    However, instance methods operate on instance attributes and are
    therefore invoked using a reference to an instance of the class on which
    that method will operate.  As noted earlier, this instance is an
    implicit parameter that is passed to the method when the method is
    called.  The following code segment illustrates the use of the replace
    method:
    
     >>> from datetime import date
      
>>> dt = date.today()
      
>>> print(dt)
      2012-04-10
      >>> dt.replace(month=5)
  # replace the month in the date
      object 
                              
      # referenced by dt
      >>>
      print(dt)           
      
      
2012-05-10
      
      >>> bday = date(1990, 5, 12)
      >>> bday.replace(day=14) # replace the day in the date object
                              
      # referenced by bday
      >>> print(bday)
      1990-05-14  
    
    Keep in mind that our focus in this course is on the use of existing
    classes.  You are not expected to be able to design new
    classes.