Classes and OOP in Python – Part 1

Classes are Python’s main object-oriented programming (OOP) tool. Classes are created with the statement class.

Classes generate one or more objects. Every time we call a class, we generate a new object with a distinct namespace. Each object generated from a class has access to the class’s attributes and gets a namespace of its own.

Note:
By redefining a class attributes you create a subclass.

Objects made with classes can be sliced, concatenated, indexed, and so on.

Classes will usually have functions attached to them, and the instances will have more basic data items used by the class’s functions.

The main thing to remember here is:

  • Each class statement generates a new class object
  • Each time a class is called, it generates a new instance object
  • Instances are automatically linked to the classes from which they are created

Note:
Attributes attached to instances pertain only to those single instances, but attributes attached to classes are shared by all their subclasses and instances.

When a def appears inside a class like this, it is usually known as a method, and it automatically receives a special first argument called self by convention. The self provides a handle back to the instance to be processed. Any values you pass to the method yourself go to arguments after self.

Attributes of classes and instances are not declared ahead of time, but spring into existence the first time they are assigned values.

Basic example:

>>> class MainClass:
...     def setdata(self, value):
...             self.data = value
...     def display(self):
...             print(self.data)
... 
>>> 

The first line class MainClass: – header line that lists the class name.
The next four lines make up the body of the class and it contains two functions that define the behavior of the class.

The def is an assignment and it assigns function objects to the names setdata and display in the class statement’s scope, and so generates attributes attached to the class (MainClass.setdata and MainClass.display).

Note:
Any name assigned at the top level of the class’s nested block becomes an attribute of the class.

Functions inside a class are called methods. So, we have two methods here! They can have defaults, return values, yield items on request, and so on.

So, we created the class (the MainClass) but now we have to create at least two instances.

>>> A = MainClass()
>>> B = MainClass()

At this point we have three objects, one class and two instances:

# First object (class)
>>> class MainClass:
...     def setdata(self, value):
...             self.data = value
...     def display(self):
...             print(self.data)
... 
>>> # Second object (instance)
>>>A = MainClass()
>>>
>>># Third object (instance)
>>> B = MainClass()

As you can see, the two instances start out empty but have links back to the class from which they were generated.

>>> A.setdata('Dan')
>>> B.setdata(40)

Neither A nor B has a setdata attribute of its own, so to find it, Python follows the link from instance to class; in Python this is called inheritance.

Now if we want to print the data in the terminal we will have:

>>> class MainClass:
...     def setdata(self, value):
...             self.data = value
...     def display(self):
...             print(self.data)
... 
>>> A = MainClass()
>>> B = MainClass()
>>> 
>>> A.setdata('Dan')
>>> B.setdata(40)
>>> 
>>> A.display()
Dan
>>> B.display()
40
>>>

As I said before, in Python you can code hierarchies of classes with specialized behavior by redefining attributes in subclasses that appear lower in the hierarchy. In this way we override the more general definitions of those attributes higher in the tree. The further down the hierarchy we go, the more
specific the software becomes.

To make a class inherit attributes from another class, just list the other class in parentheses in the new class statement’s header line. The class that inherits is called a subclass, and the class that is inherited from is its superclass.

Each instance gets names from the class it’s generated from, as well as all of that class’s superclasses.

Let’s try to illustrate the role of inheritance by extending our example:

>>> class ChildOneClass(MainClass):
...     def display(self):
...             print('Current value = "%s"' % self.data)

The ChildOneClass defines the display() method to print with a different format. By defining an attribute with the same name as an attribute in MainClass, the ChildOneClass replaces the display attribute in its superclass.

>>> C = ChildOneClass()
>>> C.setdata(41)
>>> C.display()
Current value = "41"

The code in the ChildOneClass is completely external to the MainClass . It doesn’t affect existing or future MainClass objects.

>>> A.display()
Dan
>>> B.display()
40
>>> C.display()
Current value = "41"

Leave a Reply