CMU 15-112: Fundamentals of Programming and Computer Science
Week 5: Object-Oriented Programming



Concept Review
  1. What is the difference between a class and an instance? Write a small amount of code that creates a class and code that creates an instance.

  2. For each question, fill in the circle for of the most correct answer.

    1. What is a Class in Python?
      • A template
      • A specific item
      • A specialized function
      • An inheritance
    2. What is an Instance in Python?
      • A template
      • A specific item
      • A specialized function
      • An inheritance
    3. What does it mean for a class to override a method?
      • It gets the method from its superclass
      • It gets the method from its subclass
      • It calls a method from the superclass using super()
      • It changes how the method works from the original version
    4. Which of the following can be a superclass of Student?
      • University
      • Computer Science Student
      • Course
      • Person

    5. What is the difference between __repr__(self) and __str__(self)?
      • __str__ is used when the object is converted to a string, __repr__ is used when the object is written to a file
      • __str__ is used when the object is directly converted to a string, __repr__ is used when the object is indirectly converted to a string
      • __str__ is used when the object is converted to a string, __repr__ is used when the object is hashed There is no difference.
  3. Consider the following four classes that have been implemented by the designers of a game: Monster, Player, Bat, FireBat. Assuming inheritance is properly used, fill in the following blanks. If the answer to a blank is “nothing”, then write “nothing”.
    • Monster is a subclass of ______________
    • Monster is the superclass of __________________
    • Player is a subclass of _____________
    • Player is the superclass of ___________
    • Bat is a subclass of ______________
    • Bat is the superclass of ______________
    • FireBat is a subclass of _____________
    • FireBat is the superclass of _____________
  4. Consider the following class:
    class circle: def __init__(self,r): self.radius = r def getRadius(self): return self.r a.
    1. Given the following code:
      c = circle(20)
      .Which of the following statements are correct (Mark all correct answers)?
      1. circle is an object
      2. c refers to an object)
      3. circle(20) creates a circle object
      4. c is the class circle
      5. None of the above
    2. Assume that the list allCircles contains objects of type circle, write code that will print the radius of each circle. You must use the getRadius function..
      allCircles = [ ] …
                      #assume that a bunch of circle objects have been added to the list
    3. A “point” class that is described below:
      class point: def __init__(self,x,y,col): self.x = x self.y = y self.c = col a.
      1. Add a new function called getQuadrant to this class that checks which quadrant this point is in the Cartesian coordinates.The following image shows how the four quadrants are defined.Your function should return 1 for first quadrant, 2 for second, and so on.

      2. Add another function to this class that takes another point as input parameter and checks if the two points are in the same quadrant.For this you can assume that the getQuadrant function of part “a” works. You must use the getQuadrant function.
  5. The following definition of a TeaPot class is given:
    class TeaPot(object): def __init__(self,capacity,ounces): # max amount of tea that the pot can hold self.size = capacity # total tea currently in the pot self.ouncesRemaining = ounces def fillUp(self): self.ouncesRemaining = self.size def getOuncesRemaining(self): return self.ouncesRemaining
    Write a function called pourOut for the TeaPot class, that takes one integer value, the amount of ounces to be poured, and attempts to pour out this much tea. However, if there is not enough tea left, then it pours out tea until the pot is completely empty. The function returns the number of ounces poured out. Make sure that the state of the teapot is consistent after the tea is poured out.
            def pourOut(self, amount):
                #Put your code here
            

Code Tracing
What will this code print? Figure it out by hand, then run the code to confirm. Then slightly edit the code and try again.


Free Response (Problem-Solving)


  1. Books
    Write the Book class so that it passes testBookClass, and uses the OOP constructs we learned this week as appropriate.
    def testBookClass(): print("Testing Book class...", end="") # A Book has a title, and author, and a number of pages. # It also has a current page, which always starts at 1. There is no page 0! book1 = Book("Harry Potter and the Sorcerer's Stone", "J. K. Rowling", 309) assert(str(book1) == "Book") book2 = Book("Carnegie Mellon Motto", "Andrew Carnegie", 1) assert(str(book2) == "Book") # You can turn pages in a book. Turning a positive number of pages moves # forward; turning a negative number moves backwards. You can't move past # the first page going backwards or the last page going forwards book1.turnPage(4) # turning pages does not return assert(book1.getCurrentPage() == 5) book1.turnPage(-1) assert(book1.getCurrentPage() == 4) book1.turnPage(400) assert(book1.getCurrentPage() == 309) assert(str(book1) == "Book") book2.turnPage(-1) assert(book2.getCurrentPage() == 1) book2.turnPage(1) assert(book2.getCurrentPage() == 1) # You can also put a bookmark on the current page. This lets you turn # back to it easily. The book starts out without a bookmark. book3 = Book("The Name of the Wind", "Patrick Rothfuss", 662) assert(str(book3) == "Book") assert(book3.getBookmarkedPage() == None) book3.turnPage(9) book3.placeBookmark() # does not return assert(book3.getBookmarkedPage() == 10) book3.turnPage(7) assert(book3.getBookmarkedPage() == 10) assert(book3.getCurrentPage() == 17) assert(str(book3) == "Book") book3.turnToBookmark() assert(book3.getCurrentPage() == 10) book3.removeBookmark() assert(book3.getBookmarkedPage() == None) book3.turnPage(25) assert(book3.getCurrentPage() == 35) book3.turnToBookmark() # if there's no bookmark, don't turn to a page assert(book3.getCurrentPage() == 35) assert(str(book3) == "Book") # Finally, you should be able to compare two books directly book5 = Book("A Game of Thrones", "George R.R. Martin", 807) book6 = Book("A Game of Thrones", "George R.R. Martin", 807) book7 = Book("A Natural History of Dragons", "Marie Brennan", 334) book8 = Book("A Game of Spoofs", "George R.R. Martin", 807) assert(book5 == book6) assert(book5 != book7) assert(book5 != book8) book5.turnPage(1) assert(book5 != book6) book5.turnPage(-1) assert(book5 == book6) book6.placeBookmark() assert(book5 != book6) print("Done!")

  2. Students
    Define class(es) so that testStudentOOP will pass! Make sure to use inheritance properly!
    def testStudentOOP(): print("Testing Student Classes...", end="") chaya = Student("Chaya", "Comp Bio") chaya.addClass("76-100") kyle = OneTwelveStudent("Kyle", "IS", "JJ") kyle.addClass("76-100") assert(chaya.classes == set(['76-100'])) assert(kyle.classes == set(['15-112', '76-100'])) arman = Student("Arman", "ECE") kdchin = OneTwelveStudent("Kyle", "IS", "DD") assert(chaya != arman) assert(kyle != kdchin) assert(type(arman) == Student) assert(type(kyle) == OneTwelveStudent) assert(isinstance(kyle, Student)) x = 5 try: chaya.get112Grade() except: x = 4 assert(x == 4) assert(kyle.get112Grade() == 42) kyle.study112() assert(kyle.get112Grade() == 42 + 42) assert(sorted(str(Student.students)) == sorted( "{Student named Chaya, OneTwelveStudent named Kyle, Student named Arman, OneTwelveStudent named Kyle}")) assert(sorted(str(OneTwelveStudent.students)) == sorted( "{OneTwelveStudent named Kyle, OneTwelveStudent named Kyle}")) assert(OneTwelveStudent.getSchool() == "Carnegie Mellon") print("Passed!")

  3. Gates
    A logic gate is a physical device that creates the functional equivalent of a logic operation in code [and, or, not]. It takes some number of input values, such as two values for and (input1 and input2), and produces a single output value. Write the Gate classes required to make the following test function work properly.
    def getLocalMethods(clss): import types # This is a helper function for the test function below. # It returns a sorted list of the names of the methods # defined in a class. result = [ ] for var in clss.__dict__: val = clss.__dict__[var] if (isinstance(val, types.FunctionType)): result.append(var) return sorted(result) def testGateClasses(): print("Testing Gate Classes... ", end="") # require methods be written in appropriate classes assert(getLocalMethods(Gate) == ['__init__', '__str__', 'numberOfInputs', 'setInput']) assert(getLocalMethods(AndGate) == ['getOutput']) assert(getLocalMethods(OrGate) == ['getOutput']) assert(getLocalMethods(NotGate) == ['getOutput', 'numberOfInputs']) # make a simple And gate and1 = AndGate() assert(type(and1) == AndGate) assert(isinstance(and1, Gate) == True) assert(and1.numberOfInputs() == 2) and1.setInput(0, True) and1.setInput(1, False) # Hint: to get the name of the class given an object obj, # you can do this: type(obj).__name__ # You might do this in the Gate.__str__ method... assert(str(and1) == "And(True,False)") assert(and1.getOutput() == False) and1.setInput(1, True) # now both inputs are True assert(and1.getOutput() == True) assert(str(and1) == "And(True,True)") # make a simple Or gate or1 = OrGate() assert(type(or1) == OrGate) assert(isinstance(or1, Gate) == True) assert(or1.numberOfInputs() == 2) or1.setInput(0, False) or1.setInput(1, False) assert(or1.getOutput() == False) assert(str(or1) == "Or(False,False)") or1.setInput(1, True) assert(or1.getOutput() == True) assert(str(or1) == "Or(False,True)") # make a simple Not gate not1 = NotGate() assert(type(not1) == NotGate) assert(isinstance(not1, Gate) == True) assert(not1.numberOfInputs() == 1) not1.setInput(0, False) assert(not1.getOutput() == True) assert(str(not1) == "Not(False)") not1.setInput(0, True) assert(not1.getOutput() == False) assert(str(not1) == "Not(True)") print("Passed!") testGateClasses()

  4. Building
    Write the classes Building and School so that they pass the following test cases. You may not hardcode any test cases. You must use inheritance appropriately.
    # A building is either open or closed. It starts out open. b = Building() assert(str(b) == "Building(Closed=False)") # A building can be closed and opened b.close() assert(str(b) == "Building(Closed=True)") b.open() assert(str(b) == "Building(Closed=False)") # A School is a Building that has students. s = School(2) assert(str(s) == "School(Students=2,Closed=False)") # You can't close a school if there are students inside ok = False try: s.close() except: ok = True assert(ok) # You can remove students, but the number of students inside can't go below 0. s.removeStudent() assert(str(s) == "School(Students=1,Closed=False)") s.removeStudent() assert(str(s) == "School(Students=0,Closed=False)") s.removeStudent() assert(str(s) == "School(Students=0,Closed=False)") # Once there are no students, then you can close the school. s.close() assert(str(s) == "School(Students=0,Closed=True)") # Check various things about inheritance assert(isinstance(b, Building) == True) assert(isinstance(b, School) == False) assert(isinstance(s, Building) == True) assert(isinstance(s, School) == True) # Buildings don't have students.... ok = False try: b.removeStudent() except: ok = True assert(ok)

  5. Stapler
    Write the classes Stapler and ElectricStapler so that the following test code runs without errors. Do not harcode against the values used in the testcases, though you can assume the testcases cover the needed functionality. You must use proper object-oriented design, including goog inheritance.
    def testStaplerClass(): # A stapler starts out full of the specified number of staples s = Stapler(50) assert(str(s) == "Stapler(50/50)") # You can staple something if the stapler has staples s.staple() assert(str(s) == "Stapler(49/50)") # You can refill the stapler to get it back to full. Full is the number of staples it started with, which # could be different # from stapler to stapler. s.refill() assert(str(s) == "Stapler(50/50)") for i in range(50): s.staple() assert(str(s) == "Stapler(0/50)") # If you try to staple while empty, nothing changes s.staple() assert(str(s) == "Stapler(0/50)") # An electric stapler always starts with 500 staples, and is unplugged e = ElectricStapler() assert(str(e) == "DeadStapler(500/500)") # You can plugin an electric stapler e.plugIn() assert(str(e) == "ElectricStapler(500/500)") # An electric stapler can also staple and refill e.staple() assert(str(e) == "ElectricStapler(499/500)") e.refill() assert(str(e) == "ElectricStapler(500/500)") # But an unplugged electric stapler can't staple, you get a "No Power" exception e.unPlug() ok = False try: e.staple() except: ok = True assert(ok) # Like a normal stapler, an electric stapler also doesn't change if you staple while empty e.plugIn() for i in range(500): e.staple() assert(str(e) == "ElectricStapler(0/500)") e.staple() assert(str(e) == "ElectricStapler(0/500)") # Checking inheritance assert(isinstance(s, Stapler) == True) assert(isinstance(s, ElectricStapler) == False) assert(isinstance(e, Stapler) == True) assert(isinstance(e, ElectricStapler) == True)

  6. Toy
    Write the classes Toy and Stuffie so that they pass the following test cases. You may not hardcode any test cases. You must use inheritance appropriately as well as avoid duplicating code needlessly.
    def testToyClass(): # A basic toy has an owner t = Toy("Susy") assert(t.getOwners() == "Susy") assert(str(t) == "Toy (owner=Susy)") # Toys can also have more than one owner t.addOwner("Johnny") t.addOwner("Zed") t.addOwner("Albus") # The order the owners are listed matters... assert(t.getOwners() == "Albus,Johnny,Susy,Zed") assert(str(t) == "Toy (owner=Albus,Johnny,Susy,Zed)") # Toy properly handles equivalence checking n = Toy("Johnny") n.addOwner("Albus") n.addOwner("Susy") n.addOwner("Zed") assert(t == n) assert(t != Toy("Billy")) assert(t != "Johnny") # A basic stuffie has an owner and a name s = Stuffie("Hamoodie", "MyBear") assert(str(s) == "Stuffie (name=MyBear, owner=Hamoodie)") # Stuffies, like Toys, can also have multiple owners s.addOwner("Fatima") # Just like Toys, order of owners listed matters... assert(s.getOwners() == "Fatima,Hamoodie") assert(str(s) == "Stuffie (name=MyBear, owner=Fatima,Hamoodie)") # Stuffie properly handles equivalence checking s = Stuffie("Hamoodie", "MyBear") assert(s == Stuffie("Hamoodie", "MyBear")) assert(s != Toy("Hamoodie")) assert(s != Stuffie("Billy", "MyBear")) a ssert(s != Stuffie("Hamoodie", "YourBear")) assert(s != 42) # Verify some inheritance rules... assert(isinstance(t, Toy) == True) assert(isinstance(t, Stuffie) == False) assert(isinstance(s, Toy) == True) assert(isinstance(s, Stuffie) == True)