0

I was working on stacks and stumbled into the following problem: The code is:

class stack_element(object):
    element = None

    @classmethod
    def __init__(self, value):
        print "Created element {0}".format(value)
        self.element = value

    @classmethod
    def get(self):
        return self.element

    def print_element(self):
        print self.element

class stack (object):
    stack_list = []

    @classmethod
    def push (self, value):
        self.stack_list.append(stack_element(value))

    def pop(self):
        if len(self.stack_list) > 0:
            element = self.stack_list.pop()
            return element.get()
        else:
            return None

    def print_stack(self):
        print "-------------> Stack length is {0}".format(len(self.stack_list))
        print "Elements are:"
        for i in self.stack_list:
            print "Element is {0}, element content is {1}".format(i, i.get())
        print "End of stack"

    def __iter__(self):
        return self

    def next(self):
        return self


def execute():
    mystack = stack()
    mystack.print_stack()
    mystack.push("Anna")
    mystack.print_stack()
    mystack.push("Nina")
    mystack.print_stack()

    while mystack.pop() != None:
        mystack.print_stack()

if __name__ == "__main__":
    execute()

And the output strangely enough is:

-------------> Stack length is 0
Elements are:
End of stack
Created element Anna
-------------> Stack length is 1
Elements are: Element is <__main__.stack_element object at 0x7f3067a24690>, Element content is Anna
End of stack
Created element Nina
-------------> Stack length is 2
Elements are:
Element is <__main__.stack_element object at 0x7f3067a24690>, element content is Nina
Element is <__main__.stack_element object at 0x7f3067a24710>, element content is Nina
End of stack
-------------> Stack length is 1
Elements are:
Element is <__main__.stack_element object at 0x7f3067a24690>, element content is Nina
End of stack
-------------> Stack length is 0
Elements are:
End of stack

As you can see in the second step the stack object address doesn't change, but the object content is altered. I am not doing anything particularly fancy here. Can someone please explain?

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Blade1024
  • 71
  • 6
  • Out of curiosity, why are you using so many class methods in the first place? Making `__init__` a `classmethod` is... a very strange concept and the direct cause of your strange output. None of this needs to use classmethods *at all*, and you should avoid making `stack_list` a class attribute too. – Martijn Pieters Oct 12 '16 at 13:36
  • Hi Martijn, the us of init helps to make the code somewhat easier especially during the class creation and potentially wrap it into the cycle. Why should I avoid making stack_list a class attribute? From my point of view it is should be a part of the class and be operated by class methods only with the visibility within the class only, so I can understand if we can call it a __stack_list__ to make the scoping right. Just for your info - I am not a professional developer. I appreciate if you can help with the answer though. – Blade1024 Oct 12 '16 at 14:03
  • Class attributes are *shared between instances*. You have just one list, not a per-instance list, so creating multiple `Stack` instances would share that list and the data in it. I have no idea about what you mean by 'potentially wrap it into the cycle'. If you are not an experienced developer, stay away from class methods until you understand what they actually do. – Martijn Pieters Oct 12 '16 at 14:05
  • Martijn, thank you for appointing me into the right direction - this is big surprise and disappointment to me. As per your "stay away" comment I can say that the only way to learn is to get the hands dirty. Regards – Blade1024 Oct 12 '16 at 14:14
  • Actually your answer doesn't explain the behavior. The stack_list is the only list used and operations on it are done via standard interface. What explains it is a classmethod which alters operations to the class and not the instance. Everything started to function as expected once I have disabled these statements. – Blade1024 Oct 12 '16 at 14:59
  • No, but you are setting a class attribute on `stack_element`, because `__init__` is a class method. That binds the first argument (`self` here), to the class object, so `self.element = value` is the same thing as `stack_element.element = value`. The attribute is shared. – Martijn Pieters Oct 12 '16 at 15:07

0 Answers0