Lecture Notes
Introduction to Programming and Algorithm Design (COP-1000)

Classes and objects

This chapter introduces object-oriented and programming by explaining how to construct user-defined classes. These classes can be used by a client to instantiate objects of these classes. The next two chapters will show you how to add additional functionality to your classes.


15.1 User-defined compound types

  • A user-defined type is called a class
  • Here is the syntax for a class definition:

        class ClassName:
            body
     
  • The ClassName is any valid Python identifier; the body of the class definition we will use to define the attributes of the class its instance variables (data) and methods (operations), but you can start out with nothing but a ClassName for your type:

    >>> class Point:
            pass
     
  • The name of the new type is Point (by convention, all ClassNames begin with an uppercase letter, to distinguish them from variables); the keyword pass is null operation that does nothing it's used here as a placeholder, just because every class definition has to have a body
  • Once you have defined a class, you can create objects of this type; an object is called an instance of the class, and the process of creating an object is called instantiation
  • To instantiate an object, call its constructor, a function with the same name as the class:

    >>> blank = Point()
    >>> type(blank)
    <type 'instance'>
    >>> print blank
    <__main__.Point instance at 0x00C44710
     
  • The identifier blank now refers to an object (or, if you prefer, an instance); it is called an object reference

15.2 Attributes

  • So far, all we have is a new type with no attributes sort of an empty container
  • An attribute is a named data item that makes up an instance
  • To add an attribute to an instance, use normal variable names with dot notation:

    >>> blank.x = 3.0
    >>> blank.y = 4.0
    >>> print blank.x
    3.0
    >>> print blank.x + blank.y
    7.0
     
  • Notice we have added attributes only to the instance blank not to the class Point:

    >>> p = Point()
    >>> print p.x

    Traceback (most recent call last):
    File "<pyshell#17>", line 1, in <module>
    print p.x
    AttributeError: Point instance has no attribute 'x'
     
  • You can pass an instance (remember, this is just another name for object) to a function; here the parameter is t, and will be a reference to a Point object

    >>> def showPoint(t):
            print '(' + str(t.x) + ', ' + str(t.y) + ')'

    >>> showPoint(blank)
    (3.0, 4.0)
     
  • See the sample program point1.py

15.3 Rectangles

  • Consider a new class (type) to represent rectangles; start with:

    >>> class Rectangle:
            pass
     
  • Now consider what data attributes the class should have; how do you describe a Rectangle? possibilities:
    • Two points specifying opposite corners
    • One point specifying a corner, and a height and width
    • Others?
  • Here is one possibility, using corner, height and width:

    >>> r = Rectangle()
    >>> r.width = 10.0         # width attribute
    >>> r.height = 20.0        # height attribute
    >>> r.corner = Point()     # corner attribute is a Point
    >>> r.corner.x = 0.0       # x attribute of corner
    >>> r.corner.y = 0.0       # y attribute of corner
     
  • The dot operator composes just like function composition; the last line above means "the y attribute of the corner attribute of the Rectangle instance r"
  • See example program rectangle1.py
    • The docstrings are used as documentation to describe what the class is; must be first thing in class definition. Type help(Point) in the Python shell after you have run the program
    • Both ...AsString functions use the % formatting operator and a format specifier strint to construct then return a string; %g means "general numeric format" display the value in either floating point or scientific notation, whichever is more compact

15.4 Sameness

  • What do we mean when we ask if two objects are equal? Possibilities are:
    • Two object references refer to the same object (aliases)
    • Two object references refer to different objects that have the same attributes (copies)
  • Follow this case for the first possibility:

    >>> p1 = Point()
    >>> p1.x = 3.0
    >>> p1.y = 4.0
    >>> p2 = p1         # assign object reference
    >>> p2 == p1        # are they equal?
    True
    >>> showPoint(p1)
    (3.0, 4.0)
    >>> showPoint(p2)
    (3.0, 4.0)
    >>> print id(p1), id(p2)
    12895536 12895536         # same object!
     
  • Here is a case testing the second possibility:

    >>> q1 = Point()
    >>> q1.x = 1.0
    >>> q1.y = 2.0
    >>> q2 = Point()
    >>> q2.x = 1.0
    >>> q2.y = 2.0
    >>> q1 == q2         # are they equal?
    False
    >>> showPoint(q1)    # same attributes
    (1.0, 2.0)
    >>> showPoint(q2)
    (1.0, 2.0)
    >>> print id(q1), id(q2)
    12895616 12895376          # different objects
     
  • The above shows that the == operator will only compare object references, not object attributes; if two object references are equal, this is called shallow equality
  • To test if two object's attributes are equal deep equality we will need to write a function:

    >>> def samePoint(a, b):
            if (a.x == b.x) and (a.y == b.y):
                return True
            else:
                return False

    >>> samePoint(q1, q2)   # deep equality
    True
    >>> samePoint(p1, q1)   # deep inequality
    False
    >>> samePoint(p1, p2)   # shallow equality => deep equality
    True

15.5 Instances as return values

  • Functions can return instances
  • Here is the definition of a function findCenter(), that takes a Rectangle as a parameter and returns a Point instance representing the center of the Rectangle:

    >>> def findCenter(box):
            p = Point()
            p.x = box.corner.x + (box.width / 2.0)
            p.y = box.corner.y + (box.height / 2.0)
            return p
     
  • See if this works, using Rectangle r as instantiated above:

    >>> center = findCenter(r)
    >>> showPoint(center)
    (5.0, 10.0)

15.6 Objects are mutable

  • Objects are mutable, which means their attributes are mutable:

    >>> showPoint(q1)
    (1.0, 2.0)
    >>> q1.x = q1.x * 8
    >>> showPoint(q1)
    (8.0, 2.0)

15.7 Copying

  • You can't make a copy of an object with the assignment operator, which will only assign an object reference, as we have seen above
  • The copy module contains two functions that can create a copy of an object:
    • copy returns an instance which is a complete copy of its argument, but if the instance it is copying contains object references, just the object references are copied (creating aliases); this is called a shallow copy
    • deepcopy returns an instance that is a complete copy of its argument, and recursively creates copies of all objects in the copied instance; this is called a deep copy
  • Example of a shallow copy:

    >>> import copy
    >>> r2 = copy.copy(r)       # create a shallow copy
    >>> print id(r), id(r2)
    12872200 12917816           # they are different objects
    >>> print id(r.corner), id(r2.corner)
    12871960 12871960           # but attributes are aliases
     
  • Example of a deep copy:

    >>> rd = copy.deepcopy(r)   # create a deep copy
    >>> print id(r), id(rd)
    12872200 12916936           # different object
    >>> print id(r.corner), id(rd.corner)
    12871960 12916216           # attributes are different objects
     
  • Take a look at the Python help for the copy module for more information
 Updated: 12.13.2010