Skip to main content

Python S-expression emulation using tuple-like objects.

Project description


Build Status Coverage Status PyPI

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.eval_obj

Evaluated etuples are cached:

>>> et = etuple(add, "a", "b")
>>> et.eval_obj

>>> et.eval_obj is et.eval_obj

Reconstructed etuples and their evaluation results are preserved across tuple operations:

>>> et_new = (et[0],) + et[1:]
>>> et_new is et
>>> et_new.eval_obj is et.eval_obj

rator, 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))

rator and rands are multipledispatch functions that can be extended to handle arbitrary objects:

from etuples.core import ExpressionTuple
from 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.eval_obj is add_node

etuplize 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 etuples

To install from source:

git clone
cd etuples
pip install -r requirements.txt

Tests can be run with the provided Makefile:

make check

Project details

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Files for etuples, version 0.1.4
Filename, size File type Python version Upload date Hashes
Filename, size etuples-0.1.4-py3-none-any.whl (11.1 kB) File type Wheel Python version py3 Upload date Hashes View
Filename, size etuples-0.1.4.tar.gz (22.1 kB) File type Source Python version None Upload date Hashes View

Supported by

AWS AWS Cloud computing Datadog Datadog Monitoring DigiCert DigiCert EV certificate Facebook / Instagram Facebook / Instagram PSF Sponsor Fastly Fastly CDN Google Google Object Storage and Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Salesforce Salesforce PSF Sponsor Sentry Sentry Error logging StatusPage StatusPage Status page