Home » python » A First Taste of Object Orientated Programming with Python

A First Taste of Object Orientated Programming with Python

1. Objects, attributes, methods and __init__

A class is a recipe for an object, objects are instantiations of a class. For instance the class may be ‘Person’, and the instantiation might be ‘Bob’. Objects give us a natural way of thinking about code, instead of just having functions and variables, we have things that mirror those things we are trying to model. Basically it gives you a way to create your own data structure. Let’s do an example, and let me warn you: this post will have a star trek theme! See if you can spot it.

Publicity photo of Leonard Nimoy and William S...

Publicity photo of Leonard Nimoy and William Shatner as Mr. Spock and Captain Kirk from the television program Star Trek. (Photo credit: Wikipedia)

 

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

    def say_name(self):
        print 'My name is %s.' % self.name

    def greeting(self):
 

So the class is called ‘IntelligentLifeForm’, the ‘object’ part in brackets is just something technical that I add in to make it compatible with certain Python 3 behaviours. As you can see, classes have what look like function definitions inside them.

We call these ‘methods’ or ‘class methods’. The funny looking one, ‘__init__’ has a special function: whenever an object is made, it runs init.

In addition to methods, classes also have variable or attributes, these you declare in init like ‘self.attribute’. The ‘self’ thing you see everywhere just means that it is referring to the object itself, and every method needs self as an argument. So how do we make an IntelligentLifeForm? Easy, we type:

CrystalEntity = IntelligentLifeForm(name='Crystal Entity')
print CrystalEntity.name
CrystalEntity.say_name()
CrystalEntity.greeting()
#OUTPUT
Crystal Entity
My name is Crystal Entity.

So all you do is call it like a function, passing whatever arguments that init asks for. Notice that attributes can accessed using the ‘.’ syntax directly, or indirectly through calling a method.

2. Inheritance

One of the most useful ideas in object orientated programming is inheritance, this allows us to create new classes that inherit features from a parent class, allowing us to be more specific, whilst avoiding code duplication. The best way to explain it is by doing it.

class Human(IntelligentLifeForm, object):
    def greeting(self):
        print 'Howdy!'

    def act_emotional(self):
        print 'KHAAAN!!!'

Kirk = Human(name='Kirk')
Kirk.greeting()
Kirk.say_name()
Kirk.act_emotional()

#OUTPUT
Howdy!
My name is Kirk.
KHAAAN!!!

So to inherit from a class, just add it to the class definition arguments. The new class will be exactly the same as the old one, except that we can declare new methods, like act_emotional, or override inherited methods, like greeting. After you play with this for a bit, you may wonder: how can I change behaviours instead of just overriding them? The answer is super.

class Vulcan(IntelligentLifeForm, object):
    def __init__(self, time_till_Pon_farr=7, **kwargs):
        self.time_till_Pon_farr = time_till_Pon_farr
        super(Vulcan, self).__init__(**kwargs)
    def greeting(self):
        print 'Live long and prosper.'

    def act_logical(self):
        print 'It is logical.'

Tpol=Vulcan(time_till_Pon_farr=3, name='T\'Pol')
print Tpol.time_till_Pon_farr
#OUTPUT
3

So as you see when you call super, it gives you access to the methods of the parents, which is especially useful if you want to extend init, but can be used in any method. Also notice the kwargs argument to init, this refers to keyword arguments, it anticipates and stores an arbitrary number of keyword arguments, which you can then pass into another function. More on this in my forthcoming post on decorators.

3. Multiple Inheritance

What if you want to inherit from more than one class? Well this is not generally advised if possible, because it creates a problem of precedence when the parents have methods or attributes of the same name. We’ll see how this turns out in the following.

class ChildOfTwoWorlds(Vulcan, Human):
    pass

Spock = ChildOfTwoWorlds(name='Spock', time_till_Pon_farr=6)
Spock.greeting()
Spock.say_name()
Spock.act_logical()
Spock.act_emotional()
#OUTPUT
Live long and prosper.
My name is Spock.
It is logical.
KHAAAN!!!

So ChildOfTwoWorlds inherits from both the Vulcan and Human classes, and they from IntelligentLifeForms. The order in which the arguments are given in the class definition is important! It determines priority. Here we see that since Vulcan is before Human, ChildOfTwoWorlds uses the Vulcan greeting and not the Human. This example is simple, but it could quickly get difficult to manage.

4. Composition

Composition is a way of reusing code without inheritance and should probably be used where possible, as it avoids the complexities of class hierarchies.

It is used when you can think of one object as having parts that are other objects. For example:

class StarShip(object):
    def __init__(self, crew):
        self.crew=crew

    def go_to_warp(self, warp_factor):
        print 'Ahead warp factor %i.' % warp_factor

    def shields_up(self):
        print 'Shields up!'

Enterprise = StarShip(crew=[Kirk, Spock])
Enterprise.go_to_warp(8)
#OUTPUT
Ahead warp factor 8.

For less trivial examples, the composed class will want to access the methods and attributes of its parts.

5. Dynamic Inheritance

This final section concerns another problem of reusing code, where two classes are very similar, and differ only in who they inherit from. You could of course define each separately, but code duplication is a sin! So what I will do is wrap the class definition in a function that takes the parent class as an argument, like this:

def return_starfleet_officer_class(Species):
    class Starfleet_Officer(Species, object):
        def __init__(self, rank, **kwargs):
            self.rank=rank
            super(Starfleet_Officer, self).__init__(**kwargs)
    return Starfleet_Officer
Spock = return_starfleet_officer_class(ChildOfTwoWorlds)(name='Spock', rank='Commander')
Spock.greeting()
Spock.say_name()
Spock.act_logical()
Spock.act_emotional()
print Spock.rank
#OUTPUT
Live long and prosper.
My name is Spock.
It is logical.
KHAAAN!!!
Commander

6. Next Time

There you have it, next time we will look at a another way of avoiding code duplication – decorators.

Advertisements

3 Comments

  1. […] time we are going to combine the lessons learned about objects and decorators in Python, and about graph theory, to represent graphs as […]

  2. […] and some related topics in python programming, you can read about object orientated programming here, decorators in python here, and how to represent graphs in python here and here. Note that to […]

  3. […] A First Taste of Object Orientated Programming with Python […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: