Your pop
function has an error in it. Nevermind that this is using a linked list implementation - I think that Austin Hastings does a good job at explaining that you might want to use an in-built list, but as-is, if I try and pop from the list, it isn't adjusting the stack size, so it doesn't get to the proper error-handling case for an empty stack.
Consider the following test program, executed in the Python shell directly (for my purposes, I made stack
become Stack
since I use a local stack
variable to hold the stack. I suggest you make the class name called Stack as such.):
>>> stack = Stack()
>>> stack.size
0
>>> stack.push("Test1")
>>> stack.size
1
>>> stack.push("Test2")
>>> stack.size
2
>>> stack.push("Test3")
>>> stack.size
3
>>> stack.pop()
'Test3'
>>> stack.pop()
'Test2'
>>> stack.pop()
'Test1'
>>> stack.size
3
>>> stack.pop()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/teward/pytmp/stackimplementation.py", line 18, in pop
item = self.head.val
AttributeError: 'NoneType' object has no attribute 'val'
>>>
As you can see, when you pop an object, it's not properly decreasing the value of the size of the stack, so we never hit '0' and therefore your error case.
Add a self.size -= 1
to your pop
function so we actually can hit your error case.
As I said before, I also don't see any value to the linked list implementation here. That being said, you should make your capitalization match everywhere, so class stack:
should become class Stack:
, so my test program above works. And to be 'normalized' with how you're naming your classes.
An implementation using a built-in List Object within the Class:
Now, this is a better implementation, in my opinion. It correctly implements some of the concerns by myself and Austin in that it uses an in-built list function in Python3, and some other fun bits to implement everything you individually handle. It also properly handles iteration over the stack, so you can do something like object in stack
to determine if an object is present in the stack. This can obviously be improved, of course, but helps to implement things with an internal list, and some python magic to actually get a valid stack size without having to track it as a separate value. Up to you if you want to take some inspiration here, but meh.
class Stack:
def __init__(self):
self._stack = []
@property
def size(self):
return len(self._stack)
@property
def count(self):
return self.size
def __len__(self):
return self.size
def pop(self):
if self.size == 0:
raise IndexError("Cannot pop from an empty stack.")
item = self._stack[self.size - 1]
self._stack.remove(item)
return item
def peek(self):
if self.size == 0:
raise IndexError("Cannot peek into an empty stack.")
return self._stack[self.size - 1]
def push(self, item):
self._stack.append(item)
def __iter__(self):
return iter(self._stack)
AttributeError
\$\endgroup\$list
is already effectively a stack and converting your code to use a list internally turns it into an unnecessary and inefficient wrapper. It might be more interesting to try to implement a queue or a deque, but it is probably worth noting that the latter already exists incollections.deque
. \$\endgroup\$