9.1 — Object Oriented Programming (OOP)

Objects

  • An object consists of data and a set of methods can be provided to work with it.
  • For example, a string is a collection of characters and methods like isupper or split can be called on it.
  • Python is an object-oriented language. This means that it uses objects to represent data and provides methods related to them.

Object-oriented programming (OOP)

  • Up to now, we have been using functions to organize our code, and built-in types (list, str, list, or dict) to organize our data.
  • OOP is a way to use programmer-defined data classes to organize code and data.

Class and objects

  • A class is like a blueprint/template for creating objects. It specifies what data the objects have and what methods can operate on the data.
  • An object is an instance of some class. The terms instance and object are used interchangeably.

Example — Student

We want to define a class that would be a good template for objects representing students.

Useful data:

  • Name
  • Student ID
  • Current courses
  • Past grades

Useful methods:

  • compute_GPA
  • add_course
  • drop_course

Each instance of the class (i.e., each object) would represent one particular student.

Defining a class

1# This class does not contain any useful code yet
2class MyClass:
3 """ a new data type """
4 pass
  • Class names should follow the UpperCamelCase convention.
  • In a Python file, we can define as many classes as we want.

Instantiating a class

1class Student:
2 """ Represents a student """
3 pass
4
5# We can now create an object using the constructor Student()
6student1 = Student()
7print(student1) # <__main__.Student object at 0x7fa7806c9310>
8
9student2 = Student()
10print(student2) # <__main__.Student object at 0x7fa7806c9290>

The variables student1 and student2refer to two different objects of class Student.

Attributes

  • We can create a variable that belongs to a specific object. These variables are called attributes.
  • We create an attribute by assigning it a value using the dot notation: object.attribute = value
  • Attributes can be accessed only through the object they belong to, using dot notation: object.attribute

1class Student:
2 """ Represents a student """
3 pass
4
5student1 = Student()
6# Create an attribute inside the student1 object
7student1.name = "Reza"
8
9# Use the attribute inside student1 object:
10print(student1.name) # Reza
11
12student2 = Student()
13print(student2.name)
14# AttributeError: 'Student' object has no attribute 'name'
15
16print(name) # NameError: name 'name' is not defined

Visualization

Try it!

  • Define a class Student.
  • Write a function that takes as arguments a string name and an integer id_num and returns a Student object with two attributes name and id_num.
  • Write a function that takes as arguments two Student objects and returns the name of the student with the larger id_num.
  • Test the above functions by creating two objects of Student class.

Code available in the file student_example1.py.

So far, we saw how to create attributes in an object, from outside a class. That is not how we usually create attributes. It was done for demonstration purposes to understand what attributes are.

Constructor and __init__ method

  • A constructor in an expression of form MyClass(arg1, arg2, ...) which creates an object of class MyClass. For example, Student() or Student("Reza", 1234)
  • In Python, we define a special method named __init__ (known as initializer method). It is invoked automatically whenever a new object is created using a contructor.
1class MyClass:
2 def __init__(self):
3 # do something when the object is being created

Let’s write an __init__ method for the Student class that takes no arguments (besides self) and prints out “Creating a new student”.

1class Student:
2 """ Represents a student """
3
4 def __init__(self):
5 print("Creating a new student")
6
7
8# constructor without arguments:
9student1 = Student() # __init__ will be called
Output
Creating a new student

Constructor with arguments

The constructor can have arguments which are typically used to create the attributes and set their initial values.

Now, let’s modify the __init__ method to add more arguments:

  • name (string) of the student and their id_num (int)
  • Create attributes name and id_num using self and set their values to the respective arguments.

Code available in the file student_example2.py.

What happens in example above if we do not create attributes in __init__ ?

Defining Methods

We can define methods inside a class using def keyword.

Instance methods – methods that are associated or bound to instances of a class.

  • These methods are called on an instance (object) and they can access attributes specific to that instance.

1class MyClass:
2 def my_method(self, argument1, argument2, ..., argumentN):
3 # do something

The first argument of every instance method is always refers to the object on which we are calling the method.

1obj = MyClass() # Create an instance
2
3# call my_method on obj
4obj.my_method(argument1, argument2, ..., argumentN)

By convention, the first argument is always named self. (self is not a keyword! If we use any other name instead of self, it would not be an error.)

Example continued

Let’s go back to the Student class:

  • Add a method display_info() that displays the information of a student i.e. prints the attributes of the instance.

Code available in the file student_example3.py.

Understanding self