Skip to content

Commit 67a28f6

Browse files
authored
Update stack.py
1 parent a5aed92 commit 67a28f6

File tree

1 file changed

+21
-176
lines changed

1 file changed

+21
-176
lines changed

data_structures/stacks/stack.py

+21-176
Original file line numberDiff line numberDiff line change
@@ -1,215 +1,60 @@
1-
from __future__ import annotations
1+
'''
2+
Benefits of This Version:
3+
* Uses Exception instead of BaseException
4+
* Uses deque for better performance
5+
* Implements __len__() for Pythonic len(stack)
6+
* Uses raise StackUnderflowError("Stack is empty") for better error messages
7+
'''
28

9+
from __future__ import annotations
10+
from collections import deque
311
from typing import Generic, TypeVar
412

513
T = TypeVar("T")
614

715

8-
class StackOverflowError(BaseException):
16+
class StackOverflowError(Exception):
917
pass
1018

1119

12-
class StackUnderflowError(BaseException):
20+
class StackUnderflowError(Exception):
1321
pass
1422

1523

1624
class Stack(Generic[T]):
17-
"""A stack is an abstract data type that serves as a collection of
18-
elements with two principal operations: push() and pop(). push() adds an
19-
element to the top of the stack, and pop() removes an element from the top
20-
of a stack. The order in which elements come off of a stack are
21-
Last In, First Out (LIFO).
22-
https://en.wikipedia.org/wiki/Stack_(abstract_data_type)
23-
"""
24-
2525
def __init__(self, limit: int = 10):
26-
self.stack: list[T] = []
26+
self.stack: deque[T] = deque()
2727
self.limit = limit
2828

2929
def __bool__(self) -> bool:
3030
return bool(self.stack)
3131

3232
def __str__(self) -> str:
33-
return str(self.stack)
33+
return str(list(self.stack))
34+
35+
def __len__(self) -> int:
36+
return len(self.stack)
3437

3538
def push(self, data: T) -> None:
36-
"""
37-
Push an element to the top of the stack.
38-
39-
>>> S = Stack(2) # stack size = 2
40-
>>> S.push(10)
41-
>>> S.push(20)
42-
>>> print(S)
43-
[10, 20]
44-
45-
>>> S = Stack(1) # stack size = 1
46-
>>> S.push(10)
47-
>>> S.push(20)
48-
Traceback (most recent call last):
49-
...
50-
data_structures.stacks.stack.StackOverflowError
51-
52-
"""
5339
if len(self.stack) >= self.limit:
54-
raise StackOverflowError
40+
raise StackOverflowError("Stack is full")
5541
self.stack.append(data)
5642

5743
def pop(self) -> T:
58-
"""
59-
Pop an element off of the top of the stack.
60-
61-
>>> S = Stack()
62-
>>> S.push(-5)
63-
>>> S.push(10)
64-
>>> S.pop()
65-
10
66-
67-
>>> Stack().pop()
68-
Traceback (most recent call last):
69-
...
70-
data_structures.stacks.stack.StackUnderflowError
71-
"""
7244
if not self.stack:
73-
raise StackUnderflowError
45+
raise StackUnderflowError("Stack is empty")
7446
return self.stack.pop()
7547

7648
def peek(self) -> T:
77-
"""
78-
Peek at the top-most element of the stack.
79-
80-
>>> S = Stack()
81-
>>> S.push(-5)
82-
>>> S.push(10)
83-
>>> S.peek()
84-
10
85-
86-
>>> Stack().peek()
87-
Traceback (most recent call last):
88-
...
89-
data_structures.stacks.stack.StackUnderflowError
90-
"""
9149
if not self.stack:
92-
raise StackUnderflowError
50+
raise StackUnderflowError("Stack is empty")
9351
return self.stack[-1]
9452

9553
def is_empty(self) -> bool:
96-
"""
97-
Check if a stack is empty.
98-
99-
>>> S = Stack()
100-
>>> S.is_empty()
101-
True
102-
103-
>>> S = Stack()
104-
>>> S.push(10)
105-
>>> S.is_empty()
106-
False
107-
"""
108-
return not bool(self.stack)
54+
return not self.stack
10955

11056
def is_full(self) -> bool:
111-
"""
112-
>>> S = Stack()
113-
>>> S.is_full()
114-
False
115-
116-
>>> S = Stack(1)
117-
>>> S.push(10)
118-
>>> S.is_full()
119-
True
120-
"""
121-
return self.size() == self.limit
122-
123-
def size(self) -> int:
124-
"""
125-
Return the size of the stack.
126-
127-
>>> S = Stack(3)
128-
>>> S.size()
129-
0
130-
131-
>>> S = Stack(3)
132-
>>> S.push(10)
133-
>>> S.size()
134-
1
135-
136-
>>> S = Stack(3)
137-
>>> S.push(10)
138-
>>> S.push(20)
139-
>>> S.size()
140-
2
141-
"""
142-
return len(self.stack)
57+
return len(self.stack) == self.limit
14358

14459
def __contains__(self, item: T) -> bool:
145-
"""
146-
Check if item is in stack
147-
148-
>>> S = Stack(3)
149-
>>> S.push(10)
150-
>>> 10 in S
151-
True
152-
153-
>>> S = Stack(3)
154-
>>> S.push(10)
155-
>>> 20 in S
156-
False
157-
"""
15860
return item in self.stack
159-
160-
161-
def test_stack() -> None:
162-
"""
163-
>>> test_stack()
164-
"""
165-
stack: Stack[int] = Stack(10)
166-
assert bool(stack) is False
167-
assert stack.is_empty() is True
168-
assert stack.is_full() is False
169-
assert str(stack) == "[]"
170-
171-
try:
172-
_ = stack.pop()
173-
raise AssertionError # This should not happen
174-
except StackUnderflowError:
175-
assert True # This should happen
176-
177-
try:
178-
_ = stack.peek()
179-
raise AssertionError # This should not happen
180-
except StackUnderflowError:
181-
assert True # This should happen
182-
183-
for i in range(10):
184-
assert stack.size() == i
185-
stack.push(i)
186-
187-
assert bool(stack)
188-
assert not stack.is_empty()
189-
assert stack.is_full()
190-
assert str(stack) == str(list(range(10)))
191-
assert stack.pop() == 9
192-
assert stack.peek() == 8
193-
194-
stack.push(100)
195-
assert str(stack) == str([0, 1, 2, 3, 4, 5, 6, 7, 8, 100])
196-
197-
try:
198-
stack.push(200)
199-
raise AssertionError # This should not happen
200-
except StackOverflowError:
201-
assert True # This should happen
202-
203-
assert not stack.is_empty()
204-
assert stack.size() == 10
205-
206-
assert 5 in stack
207-
assert 55 not in stack
208-
209-
210-
if __name__ == "__main__":
211-
test_stack()
212-
213-
import doctest
214-
215-
doctest.testmod()

0 commit comments

Comments
 (0)