Created
December 9, 2009 13:02
-
-
Save bellbind/252453 to your computer and use it in GitHub Desktop.
[python]Spreadsheet style lazy evaluator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
__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