Skip to content

Instantly share code, notes, and snippets.

@bellbind
Created December 9, 2009 13:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bellbind/252453 to your computer and use it in GitHub Desktop.
Save bellbind/252453 to your computer and use it in GitHub Desktop.
[python]Spreadsheet style lazy evaluator
__doc__ = """Spreadsheet style lazy evaluator
"""
from collections import defaultdict
import traceback
__all__ = ["Sheet"]
class Sheet(object):
"Spreadsheet style lazy evaluation calculator"
def __init__(self, empty=0):
"- empty: value when value does not assigned at cells"
self.columns = Columns(self)
self.empty = empty
pass
def __getattr__(self, key):
return self.columns[key]
pass
class Columns(defaultdict):
def __init__(self, sheet):
self.sheet = sheet
pass
def __missing__(self, key):
v = Column(self.sheet, key)
self[key] = v
return v
pass
class Column(object):
"One column which has spread style slice semantics"
def __init__(self, sheet, key):
self.sheet = sheet
self.key = key
self.cells = Cells(self)
pass
def __getitem__(self, key):
if type(key) is slice:
# slice as spreadsheet semantics
start, stop, step = key.indices(len(self.cells))
return [self.cells[i] for i in range(start, stop + step, step)]
return self.cells[key]
def __setitem__(self, key, value):
if type(key) is slice:
raise NotImplementedError("slice assignment")
self.cells[key] = value
return
pass
class Cells(object):
"Sparse cells with evaluator"
def __init__(self, column):
self.column = column
self.cells = {}
pass
def __getitem__(self, key):
if key not in self.cells: return self.column.sheet.empty
v = self.cells[key]
if not (type(v) is str and v[0] == "="): return v
try:
code = compile(v[1:], "%s[%d]" % (self.column.key, key), "eval")
return eval(code, __builtins__.__dict__, dict(self.column.sheet.columns))
except:
traceback.print_exc()
return self.column.sheet.empty
pass
def __setitem__(self, key, value):
self.cells[key] = value
pass
def __len__(self):
keys = self.cells.keys()
return max(keys) + 1 if keys else 0
pass
# doctest
__doc__ += """
Examples:
>>> s = Sheet()
>>> s.A[1] = 10
>>> s.A[2] = 20
>>> s.A[3] = 30
>>> s.A[30] = 100
>>> s.B[0] = "=sum(A[1:3])"
>>> s.B[1] = "=B[0] * 2"
>>> s.B[0:1]
[60, 120]
"""
if __name__ == "__main__":
import doctest, sscalc
doctest.testmod()
pass
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment