Learn how you can become a Python programmer in just 12 weeks.

    We respect your privacy. Unsubscribe at anytime.

    Avoid Common Object Oriented Programming Pitfalls

    What will we cover in this tutorial?

    I did them myself. When you first learn about object oriented programming, you get exited about it and want to turn everything into objects.

    Very often it fails to make the code easier to maintain and understand. Yes, that is one core goal of creating object oriented programming, to make it easier to maintain and understand.

    Often we just turn the traditional way of programming into objects. But that is not the point. The point is to model it in an object oriented way.

    Before that, let’s just look at why we use object oriented programming.

    Step 1: Why use object oriented programming?

    When introducing object oriented programming to beginners it often introduces too many concepts at once.

    Simply because object oriented programming is awesome and can do so many things.

    Let’s just start simple with the core of the object oriented programming idea.

    We want to make your program easier to understand and maintain.

    That is the goal for any programmer. Also, when it comes to object oriented programming.

    Object oriented programming tries to make the link between the real world and the programming world as close as possible. We humans understand the objects in the real world better than we understand how a computer pushes bits and bytes around in the memory and CPU.

    Luckily, we do not need to understand all that. We just need to understand how to program the computer through a programming language.

    Object oriented programming tries to make that easier with modeling the programs with objects, which are related to the way we humans understand things.

    Let’s try with a simple example of a Stack.

    A Stack has a top and bottom, it has operations push and pop.

    How would you model the above without using object oriented programming.

    stack_size = 8
    stack = [None]*stack_size
    top = -1 # empty stack
    def pop():
        global top, stack
        if top == -1:
            return None
        else:
            top -= 1
            return stack[top + 1]
    def push(element):
        global top, stack, stack_size
        if top + 1 >= stack_size:
            stack += [None]*stack_size
            stack_size *= 2
        top += 1
        stack[top] = element
    def print_stack():
        global top, stack, stack_size
        for i in range(top + 1):
            print(stack[i], '', end='')
        print(" (size: " + str(stack_size) + ")")
    
    print_stack()
    for i in range(10):
        push(i)
    print_stack()
    for i in range(8):
        pop()
    print_stack()
    

    That is confusing code, right?

    First of all, we use global variables. That makes the function calls hard to understand, as they have side effects.

    This is made more confusing than necessary. It does use Python lists like an Array. That is not needed, but it is just to exemplify how difficult it is to make intuitive code if you model the world like a computer works.

    Step 2: Using object oriented programming to solve the above (first step – the less bad, but still not good solution)

    First time you are asked to create stack using an object oriented approach, you will probably do it in a non intuitive way.

    Say, you think of a Stack like a object. The stack is the full object.

    What does a stack consists of?

    Well items which are piled on top of each other, and you can take the top off.

    How could that be modeled?

    Often the straight forward way from a classical thinking way into the a class.

    class Stack:
        def __init__(self):
            self.stack_size = 8
            self.stack = [None]*self.stack_size
            self.top = -1 # empty stack
        def pop(self):
            if self.top == -1:
                return None
            else:
                self.top -= 1
                return self.stack[self.top + 1]
        def push(self, element):
            if self.top + 1 >= self.stack_size:
                self.stack += [None]*self.stack_size
                self.stack_size *= 2
            self.top += 1
            self.stack[self.top] = element
        def print_stack(self):
            for i in range(self.top + 1):
                print(self.stack[i], '', end='')
            print(" (size: " + str(self.stack_size) + ")")
    
    s = Stack()
    s.print_stack()
    for i in range(10):
        s.push(i)
    s.print_stack()
    for i in range(8):
        s.pop()
    s.print_stack()
    

    If you inspect the code, it is actually the same code. Which in some ways has improved it.

    1. We do not have global variables anymore. They are tied to the Stack class.
    2. The function calls push and pop are also tied to the Stack class.
    3. Also, when we use the Stack, it is clear from the context, as it is tied to the variable s, in this case.

    So what is wrong?

    Well, it is still not simple to understand what happens in the code. It takes time to understand, even with this simple code.

    The functions use variables like top and assigns it to -1 if the stack is empty. It requires you to investigate pop and the constructor to understand that.

    The key is to keep it simple.

    So how to do that?

    Step 3: A simple way to model it

    Let’s take a look at the drawing again.

    A stack.

    A stack actually consists of object on it. Hence, the stack is the abstraction that keeps objects in a specific order.

    That said, we need to model that closer, as it will be easier to understand for the reader of the code.

    The objects on the stack we will call Nodes.

    What characterizes a Node? It lies either on the bottom or on top of another Node.

    What characterizes a Stack? It knows the top of the stack and can push and pop Nodes.

    How can that be turned into code?

    class Node:
        def __init__(self, element=None, next_node=None):
            self.element = element
            self.next_node = next_node
    
    class Stack:
        def __init__(self):
            self.top = None
        def push(self, element):
            self.top = Node(element, self.top)
        def pop(self):
            element = self.top.element
            self.top = self.top.next_node
            return element
    
    s = Stack()
    for i in range(20):
        s.push(i)
    for i in range(10):
        print(s.pop(), '', end='')
    print()
    

    How is that code? Easier to understand?

    Of course, normally a Stack would as a minimum have a helper function is_empty() to return if stack is empty. That can be added easily. You see how?

    class Node:
        def __init__(self, element=None, next_node=None):
            self.element = element
            self.next_node = next_node
    
    class Stack:
        def __init__(self):
            self.top = None
        def push(self, element):
            self.top = Node(element, self.top)
        def pop(self):
            element = self.top.element
            self.top = self.top.next_node
            return element
        def is_empty(self):
            return self.top == None
    
    s = Stack()
    for i in range(20):
        s.push(i)
    while not s.is_empty():
        print(s.pop(), '', end='')
    print()
    

    Do you get the sense of it now?

    Model the code as closely to the reality we humans understand. It makes the code easy to read and understand. Hence, easy to maintain.

    Python Circle

    Do you know what the 5 key success factors every programmer must have?

    How is it possible that some people become programmer so fast?

    While others struggle for years and still fail.

    Not only do they learn python 10 times faster they solve complex problems with ease.

    What separates them from the rest?

    I identified these 5 success factors that every programmer must have to succeed:

    1. Collaboration: sharing your work with others and receiving help with any questions or challenges you may have.
    2. Networking: the ability to connect with the right people and leverage their knowledge, experience, and resources.
    3. Support: receive feedback on your work and ask questions without feeling intimidated or judged.
    4. Accountability: stay motivated and accountable to your learning goals by surrounding yourself with others who are also committed to learning Python.
    5. Feedback from the instructor: receiving feedback and support from an instructor with years of experience in the field.

    I know how important these success factors are for growth and progress in mastering Python.

    That is why I want to make them available to anyone struggling to learn or who just wants to improve faster.

    With the Python Circle community, you can take advantage of 5 key success factors every programmer must have.

    Python Circle
    Python Circle

    Be part of something bigger and join the Python Circle community.

    Leave a Comment