class GoodScopedMap: """A GoodScopedMap maps keys to values, much like a dictionary. A value put in at an inner scope shadows any outer value for the key. The outer value becomes active again when the inner scope is exited.""" ## Representation: ## self.values is a dictionary mapping keys to their current values ## self.scopes is a list used as a stack, one entry per scope ## the order of the list is from outermost to innermost ## each element is a dictionary for those keys that had values ## put in at that level; the dictionary stores the shadowed value def __init__(self): """Initialize a new GoodScopedMap""" self.values = {} self.scopes =[{}] def isLocal(self, key): """Return True if key was put into the map at the innermost scope""" return key in self.scopes[-1] def enterScope(self): """Set the map to a new scope nested inside the previous one""" self.scopes.append({}) def exitScope(self): """Exit from the current scope to the containing one""" if len(self.scopes) == 1: raise ValueError('Attempt to exit outermost scope') for (key, value) in self.scopes.pop().items(): self.values[key] = value def retrieve(self, key): """Return the value currently corresponding to key, or None""" return self.values.get(key) def getNestingLevel(self): """Return the excess of enterScope over exitScope operations""" return len(self.scopes)-1 def put(self, key, value): """Put the key/value pair in the map at the current scope""" if not self.isLocal(key): self.scopes[-1][key] = self.values.get(key) self.values[key] = value