CISC-121
20130215


Classes and Objects (Chapter 15)

Python provides many built-in data types: integers, strings, real numbers (floats) - which are single values - and lists, dictionaries, tuples - which are groups of values.   (This list is not complete - Python has other types that we have not discussed.)

We can also create our own data types - our own ways of grouping values together.  We typically do this if our program deals with "real world things" or "objects" that are described by a set of characteristics.

For example we might want to define a Picture data type.  We could decide that every picture has
        - a title, which is stored as a string
        - an artist, also stored as a string
        - a date of creation, stored as three integers, for year, month, day
        - an image, stored in png form: a nested list with one embedded list for each row, containing three colour values for each pixel
        - a geographical location, stored as two floats, for latitude and longitude

In Python we can start to define such a data type like this

class Picture(object):
    """ defines a Picture object """

This tells Python that we are going to be using a new type or class of object, and that the class is called Picture.

Note that just as with a function definition, Python expects the next line to be indented.  Since we aren't ready yet to add any details to the definition of our new data type, I'm just using an indented triple-quote comment to satisfy Python's demands.  Soon we will see how to add useful information to the definition of the class.

Defining the class doesn't actually create any objects.  We do that by instantiation, which is just a fancy word for creating an object.  The created objects are called instances of the class.

Instantiation looks like this:

picture_1 = Picture()

This creates a Picture object in memory (for now, we can just visualize it as an empty rectangle) and it makes picture_1 point to it. 

Now we can start to store information inside this box.  The variables that we store inside an object are called the attributes of the object.

picture_1.title = "Starry Night"
picture_1.artist = "Vincent van Gogh"
picture_1.year = 1889
picture_1.month = 6
picture_1.day = 15


etc.

Once we have given values to the attributes we can use them like other variables

if picture_1.year > = 1901:
        print "created after the year 1900"


It is essential to be aware that objects are like lists in that the names we give them are pointers to the location in memory where the information is stored.  Aliasing works exactly the same for objects as it does for lists.  For example

picture_2 = picture_1

does not create a new Picture object - it simply creates a new pointer, picture_2, and makes it point to the same object that picture_1 points to.

This means that

picture_2.title = "Self Portrait"
print picture_1.title

will produce the output

Self Portrait

We can have many instances of Picture objects active at the same time:

picture_2 = Picture()
picture_3 = Picture()

picture_2.title = "Persistence of Memory"

picture_3.title = "Mona Lisa"

etc.

Each of these objects has its own place in memory, and they don't interfere with each other.

Consider the three Picture objects we have designed so far.  picture_1 has year, month and day attributes, but picture_2 and picture_3 do not.  Python will let us add any attribute to any object.  Usually we take steps to try to be sure all instances of a class have the same set of attributes, but Python doesn't force this.  This means that it is sometimes important to check whether an instance has a particular attribute before we try to use the value of that attribute.  For this purpose, Python gives us the hasattr() function, which returns True or False.  We can use it like this

if hasattr(picture_1,"year"):
    print picture_1.year

Note the quotes around the attribute name in the first line - if you omit these quotes the test will not work properly.