loader image
Skip to main content
If you continue browsing this website, you agree to our policies:
x

Topic outline

  • Unit 10: Object-Oriented Programming

    We are now ready to transition into object-oriented programming, which organizes code in the form of what are referred to as classes. In Python, every variable created is an object, and, as you have already seen, each variable has access to a set of methods. This is because there exists a class definition housing the methods that a given object has access to. In this unit, you will learn how to design your own classes, create or "instantiate" objects from a given class, and write programs that apply your class designs.

    Completing this unit should take you approximately 8 hours. 

    • Upon successful completion of this unit, you will be able to:

      • explain the differences between procedural, structured, and object-oriented programming;
      • explain how classes, objects, and instances are used in object-oriented programming; and
      • implement simple programs that use classes, objects, and instances.
    • 10.1: Overview of Object-Oriented Programming

      • We have been learning, accessing, and applying methods available in Python (it would be impossible to teach Python without doing so). Although the syntax and use of these methods are inherently object-oriented, we have been using them in the context of procedural program design and in the form of structured programs. Recall that procedural programs use functions as a way of breaking a program down into a set of procedures to solve a problem. Read this page to learn why we have been arranging our programs the way we have.

      • It is important to understand how object-oriented programs differ from procedural programs. The main goal of object-oriented programming is to allow the problem being solved to dictate the class design. For instance, a house is organized as a function of its rooms: living room, kitchen, bedroom, and so on. Each room is organized as a function of its furniture and its use. Each room could define a new class containing attributes that define the furniture and methods that define their use. The process of breaking a problem down into a set of classes each with its own set of attributes and methods is called data abstraction. This process is in stark contrast to procedural programming. Read this page to see how these approaches differ.

    • 10.2: Object-Oriented Programming (OOP)

      •  Try typing these commands in Repl.it:

        a=[1,2,3,4,5]
        print(dir(a))
        

        After creating the list object, you should see that the dir command generates a complete list of methods available for operating on that object. Notice that some of the methods have a double underscore on both sides of the method name. For instance, the __add__ method has a double underscore as both a prefix and a suffix, while the append command does not. Methods that have a double underscore as both a prefix and a suffix are called "dunder methods" (for double underscore) or "magic methods". Magic methods do not need to be called explicitly. As we will see in the examples ahead, magic methods run automatically in response to some action invoked by some other command. The main point is that an object is somehow able to access a suite of methods. In this unit, you will learn how and why this is so. The first step is to master some basic terminology that will link together and reinforce terms and concepts relevant to object-oriented programming such as classes, methods, attributes, objects, instances, and so on.

      • Read this page to learn more.

      • We will now introduce Python class construction along with how to create object instances. The example below defines a class Rectangle along with various methods useful for operating on rectangles such as area and perimeter. Run the following code in Repl.it:

        class Rectangle:
        	def __init__(self,x,y):
        		self.length=x
        		self.width=y
        	def __str__(self):
        		return 'Length='+str(self.length)+' Width='+str(self.width)
        	def area(self):
        		return self.width*self.length
        	def perimeter(self):
        		return 2*self.width+2*self.length
        	def rescale(self,a):
        		self.width=a*self.width
        		self.length=a*self.length
        	def __del__(self):
        		print("This object no longer exists")
        examp1=Rectangle(3,5)
        print(type(examp1))
        print(examp1)
        print(examp1.area())
        print(examp1.perimeter())
        examp1.rescale(2)
        print(examp1)
        examp2=Rectangle(2,4)
        print(examp2)
        print(examp2.area())
        print(examp2.perimeter())
         
        examp1=42
        del examp2
        

        Some important observations:

        • The keyword class alerts Python that a new class is being defined. 
        • The class name is Rectangle and the declaration terminates with a colon (:). 
          • Generally, as a convention, the class name is capitalized.
          • All subsequent code contained within the class definition is indented.
        • Method definitions (in a manner similar to functions) commence with the def keyword and terminate with a colon (:). 
        • __init__, __del__, and __str__ are Python magic methods.
        • areaperimeter and rescale are user-defined methods contained within the Rectangle class.
        • The self variable is the object currently being referenced (more on this in a moment). 
          • In Python, self is not a reserved keyword, but it is a very strong convention to use this variable name when referring to an object within a class definition. 
        • examp1 and examp2 are objects instantiated from the class Rectangle  
          • The attributes for each object are length and width  
          • Each object is initialized with its own set of attribute values
        • The syntax of method calls such as examp1.perimeter() or examp1.rescale(2) using the dot notation should be familiar at this point in the course.

        You can think of the class definition as a brand new variable type endowed with all the attributes and methods defined within the class. The code following the class definition demonstrates how it can be used.Given the class definition, it is possible to create multiple instances called "objects". Each object has access to the methods defined within the class, but retains its own attribute values. For instance, the commands 

        examp1=Rectangle(3,5)
        examp2=Rectangle(2,4)

        will instantiate two objects from the class Rectangle: examp1 and examp2.Each object can use the class methods to compute the area, the perimeter, or rescale using the length and width provided as the input. 

        The examp1 and examp2 objects are said to be instances of the class Rectangle.At the time theRectangle(3,5) and Rectangle(2,4)commands execute, the __init__ method is automatically called. When Rectangle(3,5) executes, the length and width attributes for examp1 are set to the input values and, similarly forexamp2 when Rectangle(2,4) executes. Therefore, the __init__ method is responsible for initializing the attribute values where self is the object being referred to at the time of execution (you may see others refer to the __init__ method as a constructor). Hence, it is possible to create multiple instances from the same class. This is the beauty of object-oriented programming: each instance has its own attribute values and can reference methods available within the class definition.  

        One more important point about methods internal to a class definition must be noted. Bear in mind that self refers to the object currently being operated upon. When a method is called to operate upon an object, observe that self is an implicit parameter that is not explicitly passed. For example, in the main code, examp1=Rectangle(3,5) instantiates an object by automatically calling the __init__ method. Notice that there are two arguments passed in the Rectangle(3,5) statement. On the other hand, inside the class definition, the __init__ method has three input arguments including self which must appear first on the input argument list. As another example, consider the examp1.rescale(2) command. In this case, the input parameter is the value used to rescale the length and width attribute values internal to the examp1 object. Observe that, internal to the class definition, the rescale method has two input arguments. Again, the self argument is implicit and appears first while the scale parameter is explicitly set by the method call in the main code. Whenever a method is to be called to operate upon an object, the method definition must have self as the first input argument. After that, all subsequent input arguments should refer to parameters used within the method.

        The __del__ dunder method is referred to as the destructor and is responsible for deleting the object when its use has expired. The subject of destructors is often omitted in introductory courses. However, professional coding demands efficient memory management so that if an object is no longer being used, best practices require its removal from memory. In the above example, redefining examp1 as an integer automatically causes the destructor to run as the object has been overwritten. The del command can be used to delete a variable; hence, the destructor would run upon deleting examp2.

        The __str__ method enables the print(examp1) command to make sense. Under normal operating circumstances, Python has no idea how to print objects. If no guidance is given, Python simply outputs a 'handle' that can be used to deduce the object's location in memory. This kind of information would not be useful to a high-level programmer. The __str__ method basically gives guidance on how to apply the print command.  

        Magic methods are incredibly useful in this way because they execute in response to some action. The __init__ method runs automatically when an object is instantiated, the __del__ method automatically executes when an object is removed and the __str__ method automatically executes when a desired string operation on an object is referred to.

        To conclude, you now have a working knowledge of the following terms: class, object, instantiation, self, constructor, destructor, method, and magic method. In addition, you also know how to define a class and instantiate objects with respect to a class. Practice more examples to become comfortable with object-oriented programming.

      • Read this for more on creating classes and methods.

      • Python is packed with a vast set of magic methods. Before delving deeper into class constructions, it is a good idea to gain some more perspective on this subject.

      • This video demonstrates class construction with a balanced mix of magic methods and user-defined methods. You may need to refer back to the Basic Terminology section to understand how the __add__ and __str__ magic methods are being used.

    • 10.3: Derived Classes

      • Classes and their associated methods are incredibly useful because of their reusability. Consider the case where we want to create a Square class that operates on squares. Given that the Rectangle class already exists, it should be possible for the Square class to inherit some of the computational capabilities of the Rectangle class presented in Section 10.2 since a square is a kind of rectangle. Whenever one class is a kind of another class, inheritance should be possible.  This relationship is referred to as IS-A. Under these circumstances, a child class (e.g. Square ) can inherit the use of various methods from the parent class (e.g. Rectangle ).

        Try inserting this class definition to the code from Section 10.2, which should follow directly after the Rectangle class definition.

        class Square(Rectangle):
            def apratio(self):
                return .25*self.length

        Then add this code to your main code:

        examp3=Square(2,2) 
        print(examp3.area()) 
        print(examp3.perimeter()) 
        print(examp3.apratio())

        There are several points to note regarding the syntax and usage of inherited classes:

        The syntax class Square(Rectangle) means that Square is the child class and Rectangle is the parent class

        Square has no __init__ method.  The object examp3, which is of the  Square class, is allowed to use the __init__ method from the Rectangle parent class. Square also inherits the ability to use other parent methods, such as perimeter and areaStudy these examples to practice inheritance.

      • Read this for more on inheritance.

      • The inheritance examples we've looked at so far have been short so that we can get the basic points across. Consider this example to practice working with a larger-scale object-oriented program.

    • 10.4: Applying Object-Oriented Programming

      • This is an excellent example of boolean operations like AND, OR, and NOT. Following and implementing this example in Repl.it will help you review the OOP concepts in this unit.
    • Study Session Video Review

    • Unit 10 Review and Assessment

      • In this video, course designer Eric Sakk walks through the major topics we covered in Unit 10. As you watch, work through the exercises to try them out yourself.

      • Take this assessment to see how well you understood this unit.

        • This assessment does not count towards your grade. It is just for practice!
        • You will see the correct answers when you submit your answers. Use this to help you study for the final exam!
        • You can take this assessment as many times as you want, whenever you want.