CS 111
Spring 2018

Old version

This is the CS 111 site as it appeared on May 10, 2018.

Lab 9: Object-oriented programming

Task 0: Review classes and objects

  1. Begin by downloading the following files:

    Open point.py in IDLE. You’ll see that we’ve begun to define a class called Point that will serve as a blueprint for a new type of object. Each Point object represents a point with coordinates (x,y) in the Cartesian plane.

    Open lab9task0.txt in a text editor and fill in your answers to the questions below.

  2. Locate the constructor function that we have provided for Point objects.

    • What is this function called? What does it do?

    • What are the names of the attributes that all Point objects have? How are those attributes defined?

    • Run point.py in IDLE, and enter statements in the Shell to create two Point obejcts:

      • one called p1, with coordinates (3, 4)
      • one called p2, with coordinates (-5, -12)

      Here is a template:

      >>> p1 =           # what should go here?
      >>> p2 =           # what should go here?
      

      Once you create your Point objects, you should then be able to do the following to see the values of their attributes:

      >>> p1.x
      3
      >>> p1.y
      4
      >>> p2.x
      -5
      >>> p2.y
      -12
      
  3. By default, evaluating or printing an object will show you something that isn’t very helpful:

    >>> p1
    <__main__.Point object at 0x02DBED50>     # you may get a different hexadecimal number after the word 'at'
    

    To make it easier to display the current state of a Point object, copy the following method into your Point class:

    def __repr__(self):
        """ returns a string representation for the called Point
            object (self)
        """
        s = '(' + str(self.x) + ', ' + str(self.y) + ')'
        return s
    

    Make sure to put this method within the class definition, and indent it so that its header is aligned with the headers of the other methods that we’ve given you.

    Once you have added this method, re-run point.py in IDLE.

    Like all __repr__ methods, this method returns a string representation of an object. It will be called automatically whenever a Point object is printed, and whenever a Point object is evaluated from the Shell:

    >>> p1 = Point(3, 4)
    >>> p2 = Point(-5, -12)
    >>> p1          # calls __repr__ on p1
    (3, 4)
    >>> p2          # calls __repr__ on p2
    (-5, -12)
    >>> print(p1)   # also calls __repr__ on p1
    (3, 4)
    
  4. Examine the method called distance_from_origin() in point.py. It computes the distance of the called Point object (self) from the origin (0,0).

    Given the Point object p1 that we created above, which of the following calls would allow us to determine its distance from the origin?

    1. distance_from_origin(p1)
    2. p1.distance_from_origin(3, 4)
    3. p1.distance_from_origin()
    4. Point.distanceFromOrigin(3, 4)
    5. Point.distanceFromOrigin()

    Experiment with the calls in the Shell as needed until you find which of the calls above works. Make sure you understand how the call works, and how the method is able to access the information that it needs to compute the distance.

  5. Examine the method called move_down() in point.py. What does it do? Test it as follows:

    >>> p1 = Point(3, 4)
    >>> p1
    (3, 4)
    >>> p1.move_down(8)
    >>> p1       # what do you see?
    

    Why doesn’t move_down() need to return a value?

  6. By default, using the == operator to compare two objects compares the memory addresses of the objects. It doesn’t compare the internals of the objects. For example:

    >>> p1 = Point(3, 4)
    >>> p2 = Point(3, 4)     # a different Point object with the same coordinates
    >>> p1 == p2    # what do you see?
    
    >>> p3 = p1     # copy the reference in p1 into p3
    >>> p1 == p3    # what do you see?
    

    Make sure that you understand the results that you obtain here. You may find it helpful to draw a memory diagram to assist your understanding.

Task 1: Practice implementing methods

  1. Write a method called quadrant that returns the number of the quadrant (if any) in which the called Point object (self) falls. The method should return:

    • 1 if both coordinates are positive
    • 2 if the x coordinate is negative and the y coordinate is positive
    • 3 if both coordinates are negative
    • 4 if the x coordinate is positive and the y coordinate is negative
    • 0 if the point lies on the x-axis or y-axis

    For example:

    >>> p1 = Point(3, 4)
    >>> p1.quadrant()
    1
    >>> p2 = Point(-3, 4)
    >>> p2.quadrant()
    2
    >>> p3 = Point(-3, -4)
    >>> p3.quadrant()
    3
    >>> p4 = Point(3, -4)
    >>> p4.quadrant()
    4
    >>> p5 = Point(0, -4)
    >>> p5.quadrant()
    0
    
  2. To allow the == operator to compare the internals of the objects, override the __eq__ method. It should have the following header:

    def __eq__(self, other):
    

    and it should return True if the called Point object (self) has the same coordinates as the Point object other, and False otherwise. For example:

    >>> p1 = Point(3, 4)
    >>> p2 = Point(3, 4)     # a different Point object with the same coordinates
    >>> p3 = Point(3, 5)
    >>> p1 == p2
    True
    >>> p1 == p3
    False
    
  3. Write a method called flip that negates and swaps the coordinates of the called Point object. For example:

    >>> p1 = Point(3, -5)
    >>> p1.flip()
    >>> p1
    (5, -3)
    >>> p2 = Point(2, 8)
    >>> p2.flip()
    >>> p2
    (-8, -2)
    
  4. Write a method called in_same_quadrant that takes another Point object as a parameter and returns True if the called Point object and the other Point object are in the same quadrant, and False otherwise. If one or both of the Point objects are on an axis, the method should return False. This method should make use of the quadrant method to avoid code duplication.

    For example:

    >>> p1 = Point(3, 4)
    >>> p2 = Point(-3, 4)
    >>> p3 = Point(5, 12)
    >>> p1.in_same_quadrant(p2)
    False
    >>> p1.in_same_quadrant(p3)
    True
    >>> p4 = Point(3, 0)    # on x-axis
    >>> p5 = Point(-2, 0)   # also on x-axis
    >>> p4.in_same_quadrant(p5)
    False
    

Task 2: Understand and modify client code

  1. Download the following file: point_explorer.py

    Open it in IDLE. You will see that it contains the beginnings of a client program of the Point class. In other words, it creates and uses objects that are created according to the blueprint provided by the Point class.

  2. Examine the file, and try to determine what it’s supposed to do. Then go ahead and run the program in IDLE.

    There are some bugs in the current version of the program that you will need to find and fix. Once you do so, you should get the following output:

    p1 has coordinates (7, 24)
    p2 has coordinates (0, -7)
    (7, 24) is 25.0 units away from the origin
    (0, -7) is 7.0 units away from the origin
    moving p1 down 7 units...
    p1 now has coordinates (7, 17)
    
  3. At the bottom of the program, add code to do the following:

    1. Get the x and y coordinates of a point from the user. Use 2 separate input statements, one for the x coordinate and one for the y coordinate. Use the int() function to convert the string values returned by input() to integers, and store those integers in variables.

    2. Create a new Point object with the coordinates specified by the user, and store it in a variable called p3.

    3. Use a method call to determine the distance of p3 from the origin, and report that distance to the user.

    4. Use a method call to flip p3, and then print its new coordinates.

    5. Use a method call to determine the new quadrant of p3. If it is on an axis, report that fact to the user. Otherwise, report which quadrant p3 is in.

    6. If time permits, add some additional client code that uses other Point methods on p3.

Task 3: Submit your work

You should use Apollo to submit:

Don’t worry if you didn’t finish all of the tasks. You should just submit whatever work you were able to complete during lab.

Here are the steps:

  1. Login to Apollo, using the link in the left-hand navigation bar. You will need to use your Kerberos user name and password.
  2. Check to see that your BU username is at the top of the Apollo page. If it isn’t, click the Log out button and login again.
  3. Find the appropriate lab section on the main page and click “Upload files.”
  4. For each file that you want to submit, find the matching upload section for the file. Make sure that you use the right section for each file. You may upload any number of files at a time.
  5. Click the “Upload” button at the bottom of the page.
  6. Review the upload results. If Apollo reports any issues, return to the upload page by clicking the link at the top of the results page, and try the upload again, per Apollo’s advice.
  7. Once all of your files have been successfully uploaded, return to the upload page by clicking the link at the top of the results page. The upload page will show you when you uploaded each file, and it will give you a way to view or download the uploaded file. Click on the link for each file so that you can ensure that you submitted the correct file.