Getting Started with Object Oriented Programming in Python

Sometimes when you're writing code, you're tempting to call as many functions as you need to solve your problem, this is known as the procedural programming approach. It is ideal for short and simple programs but, if your code keeps growing it will become more complex and hard to handle with this paradigm. In those cases is when the Object-Oriented Programming approach comes to help you.

Accordingly to the Wikipedia:

"Object-oriented programming (OOP) is a programming paradigm based on the concept of "objects", which may contain data, in the form of fields, often known as attributes; and code, in the form of procedures, often known as methods."

Objects? attributes? methods? A little confusing isn't it? Well in this entry you're going to learn all these concepts which lead you to master the OOP, so let's jump in!

Table of Content

logo

Basics of OOP

The OOP has 4 pillars: abstraction, encapsulation, inheritance and polymorphism. In this entry we're going to talk about the first two only, in next entries we're going to cover the last two.

Classes and Objects

Let's begin with talking about the differences with these two concepts, a class is the definition for a given type of object, that is the data and procedures contain within the object. Let's say that this is the skeleton or design of an object, the internal structure and how it must behave. An object is a construction of the class, is also been said that is an instance of a class, that is a copy of this class assigned to a variable that lives inside the memory.

blueprint

To clarify the above let's suppose that you are building up your kitchen. Sure, you're following some kind of blueprints an engineer or designer has given to you. Well, following the analogy you can think about a class like a blueprint, and about an object like your built kitchen. In the same way as a kitchen is made from the blueprint, an object is made from a class, this is called instance of a class.

Still confusing? Don't worry I'm sure you'll get it when we start coding, but first let's talk a little bit about the attributes and the methods.

Attributes and Methods

Before we define our first class, let's understand what attributes and methods are. In plain English, an attribute is a characteristic of a class and a method is a function. For example, your kitchen has dimensions that were defined in the blueprint, it's a characteristic of your kitchen, those dimensions are attributes. Then your kitchen is used for, among other things, making food, let's say is one of its functions, analogously this is a method.

Let's jump into one example, let's define a dog class and make some instances that represent our pets (suppose all of them are dogs hehe):

class Dog:

    def __init__(self, name, age, owner, breed):

        self.name = name 
        self.age = str(age) 
        self.owner = owner
        self.breed = breed

In python we define a class using the keyword class, then we have to initialize our class with the __init__ special method. This is the first method used when object is instantiated, you can use this method to initialize the intrinsic data within the objects, for example the name, age, owner and breed of our dogs. In case you don't remember they are the dog's attributes. Now let's add a few methods:

class Dog:

    def __init__(self, name, age, owner, breed):

        self.name = name 
        self.age = str(age) 
        self.owner = owner
        self.breed = breed 

    def talk(self):
        return f'Hi! my name is {self.name}! I am {self.age} years old!' 

    def lost(self):
        return f'My owner is {self.owner}, please take me back!'

    def bark(self):
        return 'Woof woof!'

    def breed(self):
        return f'I am a {self.breed} dog!'

Now we have some abstractions of the dogs, we're going to touch this term in a more detailed way later, but basically, this means features and behaviors they have and represent them. For example a breed, or the bark sound they do. Let's construct some objects with our dog class:

if __name__ == '__main__':
    max_dog = Dog('Max', 2, 'Guido', 'beagle')

    print(max_dog.talk())
    print(max_dog.lost())

    print(max_dog.bark())
    print(max_dog.breed())
    print(max_dog.bark())

Now if we execute the code we'll have the following output:

Hi! my name is Max! I am 2 years old!
My owner is Guido, please take me back!
Woof woof!
I am a beagle dog!
Woof woof!

Pretty cool right? Every method returns a string formatted with some attributes of the class, if you are not familiar with this type of formatting check this entry.

Something to remember is that the __init__ method is a basic function definition, but as for each method, it takes as first parameter the keyword self, which is the reserved keyword used to reference the object itself inside the function, you can use any word here, but the practice recommends for this word to be self, and the Python editor will highlight this for you. After that you can use any amount of parameters to take as inputs in this method, basically you'll need to use them in such a way that is clear when you initialize this object to the real world data.

Abstraction

As we mentioned above, abstraction is a representation of reality. When we're programming we can capture the essence of any entity that is relevant to our code. To understand this let's go through an example where we're building a clock.

clock

First we start by abstracting the things (attributes and methods) that we need to take into account for our Clock Class. We can be all day discussing about the Clock and how much things we can get from it right? But let's keep it simple, even that the clock can give us the time with three handles, one for the seconds, one for the minutes, and one for the hours, it is not necessary take them all, a simpler way is that we can account the seconds from the midnight to the current time, and work all of the other properties based on this.

So for now we have one property to abstract and that is the seconds from midnight. But what about the methods? Well need to construct some functions that we can use to know the hours and minutes, but before we get into that let's talk about a simple procedure to abstract, and that is the ticking process, this process increment the clock seconds one second at a time. So we have the following as a starter.

Properties Methods
seconds tick

Now let's code this in Python:

class Clock:

    def __init__(self, hours=0, minutes=0, seconds=0):

        self.seconds = 0

        self.seconds += seconds
        self.seconds += minutes * 60
        self.seconds += hours * 3600

Something to point out, as you can see, there is a variable called self.seconds, this is also called instance variable, once it is created, this will live within the object and you can access to it from any method using the same variable name, self.seconds.

An example on how to use this is the next code.

>>> clock1 = Clock(6, 24, 15)
>>> clock2 = Clock(13, 56, 2)

Encapsulation

Even that we haven't talk about this, we have covered some about encapsulation, this is a concept in which we gather all the data inside the object itself and how we are going to manipulate this data from the outside, this is something called public interface, if you need to whether initialize or do some other manipulations to the information inside the object, you do it through its own public interface, there are the methods that you need to define for this same purpose. In this way you can get code that is maintainable in time, because if you need to modify you code, you just need to look under the hood and modify without affecting the public interface and its interaction with the outside world.

Let's begin by defining the tick method of this public interface.

class Clock:

    def __init__(self, hours=0, minutes=0, seconds=0):

        self.seconds = 0

        self.seconds += seconds
        self.seconds += minutes * 60
        self.seconds += hours * 3600

    def tick(self, seconds=1):

        self.seconds += seconds

As you can see this method changes the data or property seconds inside the object by incrementing its value by one the value provided as parameter, let's try using this method.

>>> clock1 = Clock(6, 30, 0)
>>> clock1.seconds
23400
>>> clock1.tick()
>>> clock1.seconds
23401
>>> clock1.tick(5)
>>> clock1.seconds
23406

In this example we created a clock object and initialized it with 6 hours and 30 minutes from midnight, also you can see that you can access the seconds property using dot notation, Python will allow you to access this way but it is not recommended, as practice it is recommended to use a public interface, that is a method to get this value, this is necessary in other languages.

And as you see also the tick method changes the seconds inside the object, with a value or not provided to this method. Now let's complete this class with a public interface to get or set the value of seconds in a way that means something to the real world.

class Clock:

    def __init__(self, hours=0, minutes=0, seconds=0):

        self.seconds = 0

        self.seconds += seconds
        self.seconds += minutes * 60
        self.seconds += hours * 3600

    def tick(self, seconds=1):

        self.seconds += seconds

    def get_hours(self):

        return self.seconds // 3600

    def get_minutes(self):

        return (self.seconds % 3600) // 60

    def get_seconds(self):

        return (self.seconds % 3600) % 60

    def set_hours(self, hours):

        self.seconds = self.seconds - self.get_hours() * 3600
        self.seconds = self.seconds + hours * 3600

    def set_minutes(self, minutes):

        self.seconds = self.seconds - self.get_minutes() * 60
        self.seconds = self.seconds + minutes * 60

    def set_seconds(self, seconds):

        self.seconds = self.seconds - self.get_seconds()
        self.seconds = self.seconds + seconds

    def set_time(self, hours=None, minutes=None, seconds=None):

        if hours != None:

            self.seconds += hours * 3600

        if  minutes !=  None:

            self.seconds += minutes * 60

        if seconds != None:

            self.seconds += seconds

    def get_time(self):

        result = (self.get_hours(), self.get_minutes(), self.get_seconds())
        return  result

    def reset(self):

        self.seconds = 0

So this is the entire public interface of the clock class, as you can see the method names are more readable, you can infer what these methods do, there are also some useful methods for getting or setting the time in tuples, also with a method for resetting the object. Let's code an example using some of these methods.

>>> clock1 = Clock(9, 30, 0)
>>> clock1.tick(600)
>>> clock1.get_hours()
9
>>> clock1.get_minutes()
40
>>> clock1.set_seconds(15)
>>> clock1.get_time()
(9, 40, 15)
>>> clock1.reset()
>>> clock1.get_time()
(0, 0, 0)

Finally we are going to override a Python object built-in method, and that is the __str__ which is the method used by the Python print function, the idea of this method is to return a readable representation of the clock, so let's get into that.

class Clock:

    def __init__(self, hours=0, minutes=0, seconds=0):

        self.seconds = 0

        self.seconds += seconds
        self.seconds += minutes * 60
        self.seconds += hours * 3600

    # A bunch of methods here

    def __str__(self):

        return  str(self.get_hours()) + ":" + str(self.get_minutes()) + ":" + str(self.get_seconds())

Let's do some examples.

>>> clock1 = Clock(10, 20, 10)
>>> print(clock1)
10:20:10
>>> clock1.tick(3600)
>>> print(clock1)
11:20:10

Conclusion

The advantages that you might find in Object Oriented Programming, is that your code can become more organized, in such a way that would be in time easier to understand, maintain and modify. Object Oriented Programming comes along with some other properties that you can take advantages of in order to gain more complexity and you can design your Objects to fit your needs.

So we have covered some of the basics of Python Objects so far, but this is not everything, in a next entry we will cover some advanced features of OOP. I hope you have found this entry helpful to you and can now create your own Python objects. Don't forget to share this with your Python Peers. Thanks!

0 Comments

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel