An Introduction to Python Classes

Here is a beginner’s introduction to classes in python

“Sometimes it’s worth lingering on the journey for a while before getting to the destination.” ― Richelle Mead, The Indigo Spell

1. Introduction

The concept of a class is the core of Object Oriented Programming. It defines a blue-print for constructing objects. It is a plan of how an object is laid out, including its data members, instance methods, class methods and inheritance hierarchy. Python supports object oriented programming and classes, although with certain differences from other languages like C++ and Java. In this article, we shall delve into python classes and learn how they work.

2. Defining a Class

What does a class look like? Here is a class which does nothing at all. It illustrates how you define a class.

class MyClass:
    pass

And how do you use this class? You create an instance of this class by invoking the class name as you would a function. You can then print the returned instance. Since there is nothing in the class yet, a default representation is printed.

ex = MyClass()
print ex
# prints
<__main__.MyClass instance at 0x7f4495b9a6c8>

3. Adding a Constructor

One of the most crucial aspects of constructing an object is its constructor. This is a function which gets invoked when an object of that class is constructed. It provides a place for the programmer to initialize the object’s state correctly.

Let us add a constructor to our class. The constructor is a function named __init__() defined within the class. The constructor for our class prints a message to the console when invoked.

class MyClass:
    def __init__(self):
        print 'object', self, 'constructed'

On invocation from the above code:

object <__main__.MyClass instance at 0x7fd47734eb00> constructed
<__main__.MyClass instance at 0x7fd47734eb00>

4. Passing Arguments to the Constructor

Frequently when initializing an object, we want to pass some arguments so the object’s state is well known after construction. We can do this by adding the required arguments to the __init__() method after the self argument.

class MyClass:
    def __init__(self, intArg, strArg):
        print '__init__(', intArg, ', ', strArg, ' ) invoked.'

Now when we try to create an instance without the arguments, we have an error as expected.

ex = MyClass()
print ex
# prints
TypeError: __init__() takes exactly 3 arguments (1 given)

So, pass in the required arguments and you are all right.

ex = MyClass(3, 'cats')
print ex
# prints
__init__( 3 ,  cats  ) invoked.
<__main__.MyClass instance at 0x7f11a5100b00>

5. Defining Instance Variables

The most important aspect of an object is its state. This state is stored within what are known as Instance Variables. Let us store the parameters passed to the constructor in instance variables.

class MyClass:
    def __init__(self, intArg, strArg):
        self.intArg = intArg
        self.strArg = strArg

Once these instance variables are stored, we can access and modify them whenever required. Let us define a method __str__() which is invoked when a string representation of the object is required (such as when printing).

class MyClass:
    ...
    def __str__(self):
        return 'object = (' + str(self.intArg) + ',' + self.strArg + ')'

Here is what happens when an instance of this class is created and printed.

ex = MyClass(3, 'cats')
print ex
# prints
object = (3,cats)

So the print() function uses the string representation returned by __str__() to print the object.

6. Instance Methods

Instance methods are methods that are invoked on an instance. The first argument of an instance method is always the instance object. For example, consider the class Circle with the instance method area():

import math

class Circle:
    def __init__(self, radius):
        self.r = radius

    def area(self):
        return math.pi * self.r * self.r

The instance method is invoked as obj.method().

c = Circle(3)
print 'area of the circle is: ', c.area()

7. Static or Class Members

Static (or class) members belong to the class as a whole instead of a particular instance.

Python classes support the concept of static members or class members, just as java and C++ do. Static data members are defined by assigning a value to a name within the class as shown below. The variable lives is a static member and can be referenced as Cat.lives.

class Cat:
    lives = 9
    def __init__(self, name, age):
        self.name = name
        self.age = age
        self.nlives = Cat.lives

Usage of the static member is illustrated in the __init__() method above.

The static members can be used outside of the class too:

print 'Cats have ' + str(Cat.lives) + ' lives.'
# prints
Cats have 9 lives.

8. Static or Class Methods

A static method of a class is a method common to all instances of the class rather than a particular instance. A static method must be annotated with @staticmethod annotation.

In the following example, a static data member Cat.cats maintains the names of the cats created, and the static method Cat.listCats() lists the cats currently in existence.

class Cat:
    cats = []

    @staticmethod
    def listCats():
        for cat in Cat.cats:
            print cat

    def __init__(self, name):
        self.name = name;
        Cat.cats.append(name)

Here is how the class is used.

print 'Adding Fink ..'
c1 = Cat('Fink')
Cat.listCats()

print 'Adding Dink ..'
c2 = Cat('Dink')
Cat.listCats()

# prints
Adding Fink ..
Fink
Adding Dink ..
Fink
Dink

9. Inheritance and Derived Classes

Inheritance refers to factoring out common aspects of two or more classes into a base class. The derived classes can then specialize required aspects of the base class.

In the example below, we have a base class Shape which defines the methods area() and circum().

import math

class Shape:
    tname = 'none'

    def area(self):
        pass

    def circum(self):
        pass

The derived classes Circle and Rect inherit from the base class Shape and specialize the implementation of these methods.

class Circle(Shape):
    tname = 'circle'

    def __init__(self, radius):
        self.r = radius

    def area(self):
        return math.pi * self.r * self.r

    def circum(self):
        return 2 * math.pi * self.r

class Rect(Shape):
    tname = 'rect'

    def __init__(self, width, height):
        self.w = width
        self.h = height

    def area(self):
        return self.w * self.h

    def circum(self):
        return 2*(self.w + self.h)

In client code, you can process the shape objects using the interface.

shapes = []
shapes.append(Shape())
shapes.append(Circle(3))
shapes.append(Rect(3, 4))

for s in shapes:
    print 'type = ', s.tname + ', area = ', s.area(), ', circum = ', s.circum()
# prints
type =  none, area =  None , circum =  None
type =  circle, area =  28.2743338823 , circum =  18.8495559215
type =  rect, area =  12 , circum =  14

10. Private and Protected Members

A private class member is one which cannot be accessed outside of the class where it is defined. A protected member also cannot be accessed outside of the class except by derived classes.

Python does not provide any support for implementing private or protected class members. All members of the class are public in the sense that they can be accessed outside the class without the python compiler/interpreter raising errors. To ease understanding by other programmers maintaining the code, you can define a convention to indicate private members. One such convention is to start private members with an underscore.

Conclusion

Let us review. Python classes are defined using the keyword class. The __init__() method is invoked when the class instance is created. You can define instance methods, and assign to and read from instance variables in the instance methods. Additionally you can also define static members and method.