This is part of an ongoing series on learning the Python programming language. If you haven't read them yet, I advise you to catch up on parts one, two, three, four, five, six and seven before reading this article.

Before we delve further into Python itself, at this point it is helpful to deal with objects and classes and how Python implements them. Python and many other languages are built on objects and classes and use a particular method of programming called Object Orientated Programming (otherwise known by its TLA, OOP).

Blueprints And Houses

The easiest way to explain the difference between objects and classes is to think of classes as the blueprint of a house, and an object as the actual house.

A blueprint indicates what the house should look like, defining where the walls, windows, doors, bathrooms, kitchen and other things are in the house. The blueprint, however, is not a house. It is simply a plan of what the house should look like.

Additionally, you can build several houses using that same single blueprint. The houses don't need to be identical, one might be painted blue and another red, but their structure is the same.

In the same way, a class is the design for how an object will look. Multiple objects can be created from the same class, but each object can have different values.

Note for C# and Java programmers:

Unlike other programming languages, everything in Python is an object. Both classes and functions are objects, as well as traditional primitive types like integers and booleans.

Instantiating Classes

When you create an object from a class it is called instantiation, in other words you are creating an instance of a class. Extending the terminology further, creating an object is also known as instantiating a class.

Let's look at an example of a class and an object.

class Person(object):
    """
    The `Person` class is blank for the moment.
    """
    pass

p = Person()

First the class is declared using the class keyword and the name of the class. Then we create an instance of the Person class called p.

Printing that object would show you details like its class and its location in memory.

>>> print p
<__main__.Person object at 0x7f596c91bbd0>

If we want to find out the name of the class this object is from, we can use the built-in __class__ attribute to access the class itself, and then the __name__ attribute of the class for a string containing the name.

>>> print p.__class__.__name__
Person

Functions in Classes: Methods

In Python lingo, when a function is part of a class, it has a special name; it is called a method. Additionally, methods in Python are declared slightly differently to functions. Because methods are used via the objects created from these classes, methods must take at least one parameter, which should also be the first parameter when there are other parameters present. This special parameter must be named "self" and the actual object is passed in to the method via this "self" parameter.

class Person(object):
    def get_name(self):
        return 'George'

Even if you do not use the self parameter, it should still be in the method declaration.

Like the special __name__ attribute, classes also have special methods. One of the special methods you'll be using often is the __init__ method. This method is called automatically when an object is instantiated. You can use this method to do any initial setup of the object.

Let's add that method to our Person class.

class Person(object):
    def __init__(self, name):
        self.name = name

    def get_name(self):
        return self.name

p = Person('James')
print 'Hello', p.get_name()

In this program you can see that a name was supplied when creating an instance of the Person class. Any parameters passed to the class are passed on to the __init__ method.

With the name set, the get_name method returns the name that was set in the __init__ method, using the instance attribute we set. An instance attribute is a property that is tied to a single instance of a class, in other words it is tied to a single object and only exists for the duration of that class.

Note for C# and Java programmers:

Python's __init__ method is analogous to a constructor in other object orientated programming languages. The __init__ method is not a true constructor due to the fact that the object already exists, but for the most part it acts similarly. Use the __new__ method to catch the instantiation step often used to implement the Singleton pattern.

Class and Object Variables

I've already mentioned object or instance variables, variables that only exist on a particular object. There are also class variables, variables which are attached to classes as opposed to objects.

class Person(object):
    Count = 0
    def __init__(self):
        Person.Count += 1

p = Person()
print Person.Count

q = Person()
print Person.Count

In this example, you'll see that the Count variable is being referenced via the class instead of the objects. If you run this program you should see the following output:

12

As you can see, the class variable is independent of the objects, but influenced by their explicit references to the class.

Inheritance

One of the big principles behind object orientated programming is inheritance. Just like you are a descendant of your parents and inherited some of their features (his eyes are just like his mother's!), so classes can descend from other classes and inherit their properties and methods.

You'll probably have noticed that in all the class examples so far there is always this "object" parameter for the class. This actually specifies the parents class. The most basic class in Python is the "object" class, and all classes should eventually inherit from this class.

Without diving too far down the rabbit hole of OOP principles, inherited classes have the ability to override their parent methods with their own versions of those methods. This is called polymorphism. Inherited methods can call a parent's method too, should it be necessary.

Let's look at an example of this. We'll have two classes that descend from the Person class, and implement their own methods and attributes.

class Person(object):
    def __init__(self, name):
        self.name = name

    def get_name(self):
        return self.name

class Teacher(Person):
    def __init__(self, name, subject):
        self.subject = subject
        Person.__init__(self, name)

    def get_subject(self):
        return self.subject

class Student(Person):
    def __init__(self, name, grade):
        self.grade = grade
        Person.__init__(self, name)

    def get_grade(self):
        return self.grade

Before we jump into seeing this work, let's walk through what is going on here.

Firstly we have our Person class, with its name attribute which is set using the __init__ method. Then we have a Teacher class which inherits from Person, implementing its own version of the __init__ method which saves the teacher's subject as an attribute, and then calling the parent __init__ method. Lastly we have a Student class which also overrides the inherited __init__ method with its own which sets the student's grade, and then also calls the parent method.

t = Teacher('Mr Smith', 'Computer Science')
print t.get_name(), 'teaches', t.get_subject()

s = Student('Alex Smart', 10)
print s.get_name(), 'is in grade', s.get_grade()

This would print our the following:

Mr Smith teaches Computer ScienceAlex Smart is in grade 10

Notice how each of the descendant classes has the parent class's get_name() method, but also implements their own special methods. This is inheritance in action.

Note that in Python you don't have to create get methods to return the value in an attribute, you could reference the attribute directly. We do so in the examples to make things clearer and for the sake of the example.

Note for C# and Java programmers:

Python does not have any concept of private or protected methods and attributes. In each of the examples above the attributes could have quite easily been accessed directly. By convention, if you want to indicate that an attribute or method is private you should prefix its name with an underscore, e.g. self._name.

Object orientated programming is a difficult concept to understand, and even more difficult to explain succinctly. Did you understand from the above explanation?

Update: Part 9


Comments

comments powered by Disqus