import copy class StackError(Exception): pass class Stack: """ Class to replicate a Stack data structure. Attributes: maxlen, name Methods: copy, pop, populate, push, top, truncate """ def __init__(self, maxlen=None, name=""): self.initialized = False self.maxlen = maxlen self.name = str(name) self.data = [] self.initialized = True def __get__(self): return self.data def __len__(self): return len(self.data) def __getitem__(self, index): return self.data[index] def __setattr__(self, key, value): if key == "initialized": pass elif not self.initialized: pass elif key == "name": value = str(value) elif key == "maxlen" and value is not None: if value < 0: raise StackError() if len(self) > value: sizediff = len(self) - value sizediff = str(sizediff) e = ("Cannot set `maxlen` below current `len` or %s items " "would be lost. Try Stack.pop(%s) or Stack.truncate(%d)") raise StackError(e % (sizediff, sizediff, value)) elif key == "data" and self.maxlen is not None: if len(value) > self.maxlen: raise StackError("List is longer than `maxlen` (%d/%d)" % (len(value), self.maxlen)) super(Stack, self).__setattr__(key, value) def __repr__(self): display = self.name display += "[|" display += ', '.join([item.__repr__() for item in self.data]) display += "|]" if self.maxlen is not None: display += str(self.maxlen - len(self)) return display def copy(self): """ Return a deep copy of this Stack as a new object """ copystack = Stack(self.maxlen, self.name) copystack.populate(copy.deepcopy(self.data)) return copystack def pop(self, count=1): """ Pop the last `count` items off of the Stack. Default 1 returns the most recently popped item """ for c in range(count): if len(self) == 0: raise StackError("Cannot pop from empty Stack") lastitem = self.data[-1] del self.data[-1] return lastitem def populate(self, itemlist, destructive=False): """ Push as many items as possible from `itemlist` onto the Stack if `destructive`==True, the current data will be overwritten and discard the rest. """ if isinstance(itemlist, range): itemlist = list(itemlist) if isinstance(itemlist, list): if destructive: itemlist = itemlist[:self.maxlen] self.data = itemlist else: if self.maxlen: itemlist = itemlist[:self.maxlen - len(self)] self.data += itemlist else: raise StackError("Stack.populate only accepts list or range type") def push(self, item): """ Push an item onto the end of the Stack """ if item is self: raise StackError("Cannot push Stack onto itself") if self.maxlen is None or len(self) < self.maxlen: self.data.append(item) else: raise StackError("Cannot push item onto full Stack") def top(self): """ Return the item on the top of the stack without popping it """ if len(self) > 0: return self.data[-1] else: raise StackError("Stack is empty") def truncate(self, value): """ Remove all items from the Stack after index `value`, and set `maxlen` to `value`, preventing the addition of further items. returns None """ self.data = self.data[:value] self.maxlen = value