CMU 15-112: Fundamentals of Programming and Computer Science
Class Notes: Object-Oriented Programming (OOP), Part 1
Using Objects and Methods


  1. Methods vs Functions
  2. Classes and Instances
  3. Objects and Object-Oriented Programming (OOP)
  4. Mutable Objects with Dataclass Classes
  5. Updated Example: Adding and Deleting Shapes

  1. Methods vs Functions
    We call methods using s.f() rather than f(s):
    s = 'This could be any string!' print(len(s)) # len is a function print(s.upper()) # upper is a string method, called using the . notation # we say that we "call the method upper on the string s" print(s.replace('could', 'may')) # some methods take additional arguments

    See how we get different errors for improperly calling methods vs functions:
    n = 123 print(len(n)) # TypeError: object of type 'int' has no len() # This means that len() cannot work properly with int's n = 123 print(n.upper()) # AttributeError: 'int' object has no attribute 'upper' # This means that there is no method upper() for int's

  2. Classes and Instances
    • Classes are also called "Types" in Python.
      • For example, these are classes: int, float, str, bool
    • Instances are values of a given class or type.
      • For example: 'abc' is a str instance (also called a string)

  3. Objects and Object-Oriented Programming (OOP)
    • Every value in Python is an Object.
      • Every instance is an object, and its type is some class.
      • Every class is an object, too (its type is type!).
    • That is why we call this Object-Oriented Programming
      • We are using objects only a little bit now.
      • Soon we will write our own classes.
      • Then we will add some sophistication to how we write and use classes and objects.
      • Even so, because we are using objects now, we are already using Object-Oriented Programming (OOP).

  4. Mutable Objects with Dataclass Classes
    We can use make_dataclass to create classes that we can then use to create mutable objects. This is a very handy way to store a collection of properties in a single object.
    # Don't forget this import: from dataclasses import make_dataclass # Now we can create a new class named Dog where # instances (individual dogs) have 3 properties # (fields): name, age, and breed Dog = make_dataclass('Dog', ['name', 'age', 'breed']) # Now we can create an instances of the Dog class: dog1 = Dog(name='Dino', age=10, breed='shepherd') print(dog1) # prints: Dog(name='Dino', age=10, breed='shepherd') print(dog1.name) # prints: Dino # Next, let's show that this is in fact mutable: dog1.name = 'Fred' print(dog1) # prints: Dog(name='Fred', age=10, breed='shepherd') print(dog1.name) # prints: Fred # Now let's show that the fields are in fact required: try: dog2 = Dog(name='Dino', age=10) except Exception as e: print(e) # prints: missing 1 required positional argument: 'breed' # Now let's show that == works properly: dog2 = Dog(name='Spot', age=12, breed='poodle') dog3 = Dog(name='Fred', age=10, breed='shepherd') print(dog1 == dog2) # prints: False print(dog1 == dog3) # prints: True # Finally, let's confirm that sets do not work, # since these objects are mutable: try: s = { dog1 } except Exception as e: print(e) # prints: unhashable type: 'Dog'

  5. Updated Example: Adding and Deleting Shapes
    Here is an improved version of the adding-and-deleting-shapes example from here. Instead of representing dots as (cx, cy) pairs, here we will create a Dot class using make make_dataclass. Now, each instance will use dot.cx, dot.cy, dot.r, dot.counter, and dot.color.
    from cmu_112_graphics import * import random from dataclasses import make_dataclass Dot = make_dataclass('Dot', ['cx', 'cy', 'r', 'counter', 'color']) def appStarted(app): app.dots = [ ] def pointIsInDot(x, y, dot): return (((dot.cx - x)**2 + (dot.cy - y)**2)**0.5 <= dot.r) def getRandomColor(): return random.choice(['pink','yellow','lightGreen','gold','white']) def mousePressed(app, event): # go through dots in reverse order so that # we find the topmost dot that intersects for dot in reversed(app.dots): if pointIsInDot(event.x, event.y, dot): dot.counter += 1 dot.color = getRandomColor() return # mouse click was not in any dot, so create a new dot newDot = Dot(cx=event.x, cy=event.y, r=20, counter=0, color='cyan') app.dots.append(newDot) def keyPressed(app, event): if (event.key == 'd'): if (len(app.dots) > 0): app.dots.pop(0) else: print('No more dots to delete!') def redrawAll(app, canvas): # draw the dots and their counters for dot in app.dots: canvas.create_oval(dot.cx-dot.r, dot.cy-dot.r, dot.cx+dot.r, dot.cy+dot.r, fill=dot.color) canvas.create_text(dot.cx, dot.cy, text=str(dot.counter)) # draw the text canvas.create_text(app.width/2, 20, text='Example: Adding and Deleting Shapes') canvas.create_text(app.width/2, 40, text='Mouse clicks outside dots create new dots') canvas.create_text(app.width/2, 60, text='Mouse clicks inside dots increase their counter') canvas.create_text(app.width/2, 70, text='and randomize their color.') canvas.create_text(app.width/2, 90, text='Pressing "d" deletes circles') runApp(width=400, height=400)