Python S-expression emulation using tuple-like objects.
etuples are like tuples:
>>> from operator import add >>> from etuples import etuple, etuplize >>> et = etuple(add, 1, 2) >>> et ExpressionTuple((<built-in function add>, 1, 2)) >>> from IPython.lib.pretty import pprint >>> pprint(et) e(<function _operator.add(a, b, /)>, 1, 2) >>> et[0:2] ExpressionTuple((<built-in function add>, 1))etuples can also be evaluated:
>>> et.evaled_obj 3Evaluated etuples are cached:
>>> et = etuple(add, "a", "b") >>> et.evaled_obj 'ab' >>> et.evaled_obj is et.evaled_obj TrueReconstructed etuples and their evaluation results are preserved across tuple operations:
>>> et_new = (et[0],) + et[1:] >>> et_new is et True >>> et_new.evaled_obj is et.evaled_obj Truerator, rands, and apply will return the operator, the operands, and apply the operation to the operands:
>>> from etuples import rator, rands, apply >>> et = etuple(add, 1, 2) >>> rator(et) <built-in function add> >>> rands(et) ExpressionTuple((1, 2)) >>> apply(rator(et), rands(et)) 3rator and rands are multipledispatch functions that can be extended to handle arbitrary objects:
from etuples.core import ExpressionTuple from collections.abc import Sequence class Node: def __init__(self, rator, rands): self.rator, self.rands = rator, rands def __eq__(self, other): return self.rator == other.rator and self.rands == other.rands class Operator: def __init__(self, op_name): self.op_name = op_name def __call__(self, *args): return Node(Operator(self.op_name), args) def __repr__(self): return self.op_name def __eq__(self, other): return self.op_name == other.op_name rands.add((Node,), lambda x: x.rands) rator.add((Node,), lambda x: x.rator) @apply.register(Operator, (Sequence, ExpressionTuple)) def apply_Operator(rator, rands): return Node(rator, rands)>>> mul_op, add_op = Operator("*"), Operator("+") >>> mul_node = Node(mul_op, [1, 2]) >>> add_node = Node(add_op, [mul_node, 3])etuplize will convert non-tuple objects into their corresponding etuple form:
>>> et = etuplize(add_node) >>> pprint(et) e(+, e(*, 1, 2), 3) >>> et.evaled_obj is add_node Trueetuplize can also do shallow object-to-etuple conversions:
>>> et = etuplize(add_node, shallow=True) >>> pprint(et) e(+, <__main__.Node at 0x7f347361a080>, 3)Using pip:
pip install etuplesFirst obtain the project source:
git clone git@github.com:pythological/etuples.gitCreate a virtual environment and install the development dependencies:
$ pip install -r requirements.txtSet up pre-commit hooks:
$ pre-commit install --install-hooksTests can be run with the provided Makefile:
make check