Skip to content

Instantly share code, notes, and snippets.

@internetimagery
Last active June 15, 2021 08:28
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 internetimagery/05082fac28bc17860ec23fa0d7172df7 to your computer and use it in GitHub Desktop.
Save internetimagery/05082fac28bc17860ec23fa0d7172df7 to your computer and use it in GitHub Desktop.
Experiment in "underscore" placeholder lambda generation. Detecting when to finalize and when to build.
"""
Yet another placeholder underscore lambda replacement.
This is a proof of concept trying to tackle the difficult issue of detecting when the function is still being built, and when it is being used.
>>> list(map(_.upper(), "abc"))
>>> # ["A", "B", "C"]
"""
import operator
import sys
from dis import disco, opmap
from re import finditer
from io import StringIO
from weakref import ref
from functools import partial
from itertools import chain
from collections import namedtuple
from inspect import currentframe
# Limit the search space. These declare end of an expression.
OP_EXPRESSION_STOP = frozenset(
(
"STORE_NAME",
"STORE_FAST",
"STORE_ATTR",
"STORE_SUBSCR",
)
)
# How the opcodes affect the stack
OP_STACK_MANIP = {
"POP_TOP": lambda i: -1,
"DUP_TOP": lambda i: 1,
"DUP_TOP_TWO": lambda i: 2,
"LOAD_FAST": lambda i: 1,
"LOAD_CONST": lambda i: 1,
"LOAD_NAME": lambda i: 1,
"LOAD_GLOBAL": lambda i: 1,
}
OP_STACK_MANIP.update(
(op, lambda i: -1)
for op in opmap
if op.startswith(("BINARY_", "INPLACE_", "STORE_"))
)
OP_STACK_MANIP.update(
(op, lambda i: -i[2])
for op in opmap
if op.startswith("CALL_")
)
OP_STACK_MANIP.update(
(op, lambda i: -i[2] + 1)
for op in opmap
if op.startswith("BUILD_")
)
class __(type):
""" Cause the class to instantiate when used """
def __getattr__(cls, name):
return getattr(cls(currentframe().f_back, 0), name)
def __getitem__(cls, index):
return cls(currentframe().f_back, 1)[index]
def __abs__(cls):
return abs(cls(currentframe().f_back, 0))
def __add__(cls, other):
return cls(currentframe().f_back, 1) + other
def __radd__(cls, other):
return other + cls(currentframe().f_back, 1)
def __sub__(cls, other):
return cls(currentframe().f_back, 1) - other
def __rsub__(cls, other):
return other - cls(currentframe().f_back, 1)
def __mul__(cls, other):
return cls(currentframe().f_back, 1) * other
def __rmul__(cls, other):
return other * cls(currentframe().f_back, 1)
def __truediv__(cls, other):
return cls(currentframe().f_back, 1) / other
__div__ = __truediv__ # py2
def __rtruediv__(cls, other):
return other / cls(currentframe().f_back, 1)
__rdiv__ = __rtruediv__ # py2
def __mod__(cls, other):
return cls(currentframe().f_back, 1) % other
def __rmod__(cls, other):
return other % cls(currentframe().f_back, 1)
def __pow__(cls, other):
return cls(currentframe().f_back, 1) ** other
def __rpow__(cls, other):
return other ** cls(currentframe().f_back, 1)
def __pos__(cls):
return +cls(currentframe().f_back, 0)
def __neg__(cls):
return -cls(currentframe().f_back, 0)
# COMPARISON
def __lt__(cls, other):
return cls(currentframe().f_back, 1) < other
def __le__(cls, other):
return cls(currentframe().f_back, 1) <= other
def __eq__(cls, other):
return cls(currentframe().f_back, 1) == other
def __ne__(cls, other):
return cls(currentframe().f_back, 1) != other
def __ge__(cls, other):
return cls(currentframe().f_back, 1) >= other
def __gt__(cls, other):
return cls(currentframe().f_back, 1) > other
# CANNOT SUPPORT THESE :(
def __bool__(cls):
# Only allowed to return bool, so can't use this. :(
raise TypeError("bool not supported :(")
__nonzero__ = __bool__ # py2
def __len__(cls):
# Only allowed to return int, so can't use this. :(
raise TypeError("len not supported :(")
class _(object, metaclass=__):
"""
Generic placeholder for building simple lambdas.
fn = _["key"].upper()
assert fn({"key":"lower"}) == "LOWER"
"""
def __init__(self, frame, stack):
self.__commands = []
self.__name = []
self.__code = ref(frame.f_code)
self.__end = 0
self._finalized = False
lasti = frame.f_lasti
for instruction in _get_instructions(frame.f_code):
if instruction[0] < lasti:
continue
if instruction[1] in OP_EXPRESSION_STOP:
break
manip = OP_STACK_MANIP.get(instruction[1])
if manip:
stack += manip(instruction)
if stack < 0:
break
self.__end = instruction[0]
def __abs__(self):
self.__commands.append(operator.abs)
self.__name.insert(0, f"abs(")
self.__name.append(f")")
return self
def __add__(self, other):
self.__commands.append(partial(operator.add, other))
self.__name.append(f" + {other!r}")
return self
def __radd__(self, other):
self.__commands.append(partial(operator.add, other))
self.__name.insert(0, f"{other!r} + ")
return self
def __sub__(self, other):
self.__commands.append(lambda x: x - other)
self.__name.append(f" - {other!r}")
return self
def __rsub__(self, other):
self.__commands.append(partial(operator.sub, other))
self.__name.insert(0, f"{other!r} - ")
return self
def __mul__(self, other):
self.__commands.append(partial(operator.mul, other))
self.__name.append(f" * {other!r}")
return self
def __rmul__(self, other):
self.__commands.append(partial(operator.mul, other))
self.__name.insert(0, f"{other!r} * ")
return self
def __truediv__(self, other):
self.__commands.append(lambda x: x / other)
self.__name.append(f" / {other!r}")
return self
def __rtruediv__(self, other):
self.__commands.append(partial(operator.truediv, other))
self.__name.insert(0, f"{other!r} / ")
return self
def __mod__(self, other):
self.__commands.append(lambda x: x % other)
self.__name.append(f" % {other!r}")
return self
def __rmod__(self, other):
self.__commands.append(partial(operator.mod, other))
self.__name.insert(0, f"{other!r} % ")
return self
def __pow__(self, other):
self.__commands.append(lambda x: x ** other)
self.__name.append(f" ** {other!r}")
return self
def __rpow__(self, other):
self.__commands.append(partial(operator.pow, other))
self.__name.insert(0, f"{other!r} ** ")
return self
def __pos__(self):
self.__commands.append(operator.pos)
self.__name.insert(0, f"+")
return self
def __neg__(self):
self.__commands.append(operator.neg)
self.__name.insert(0, f"-")
return self
def __lt__(self, other):
self.__commands.append(partial(operator.gt, other))
self.__name.append(f" < {other!r}")
return self
def __le__(self, other):
self.__commands.append(partial(operator.ge, other))
self.__name.append(f" <= {other!r}")
return self
def __eq__(self, other):
self.__commands.append(partial(operator.eq, other))
self.__name.append(f" == {other!r}")
return self
def __ne__(self, other):
self.__commands.append(partial(operator.ne, other))
self.__name.append(f" != {other!r}")
return self
def __ge__(self, other):
self.__commands.append(partial(operator.le, other))
self.__name.append(f" >= {other!r}")
return self
def __gt__(self, other):
self.__commands.append(partial(operator.lt, other))
self.__name.append(f" > {other!r}")
return self
def __getattr__(self, name):
if self._finalized:
raise AttributeError(f"Finalized function has no attribute {name}")
self.__commands.append(operator.attrgetter(name))
self.__name.append(f".{name}")
return self
def __getitem__(self, index):
if self._finalized:
raise TypeError("Finalized object is not subscriptable")
self.__commands.append(operator.itemgetter(index))
self.__name.append(f"[{index!r}]")
return self
def __call__(self, *args, **kwargs):
if self._finalized:
return self.__run(*args, **kwargs)
frame = currentframe().f_back
if self.__code() is not frame.f_code or frame.f_lasti > self.__end:
self._finalized = True
return self.__run(*args, **kwargs)
# Optimize with a method caller if we previously got an attribute to run it
if self.__commands and isinstance(self.__commands[-1], operator.attrgetter):
command = operator.methodcaller(self.__name[-1][1:], *args, **kwargs)
self.__commands.pop()
else:
command = partial(_call, args, kwargs)
arg_visual = (repr(a) for a in args)
kwarg_visual = ("{}={!r}".format(*i) for i in kwargs.items())
self.__commands.append(command)
self.__name.append("({})".format(", ".join(chain(arg_visual, kwarg_visual))))
return self
def __run(self, *values):
if not values:
raise TypeError("Not enough arguments supplied")
value = values[0]
for command in self.__commands:
value = command(value)
if isinstance(value, type(self)):
return value(*values[1:])
return value
def __repr__(self):
return "< _{} >".format("".join(self.__name))
def _call(args, kwargs, func):
""" Store arguments till function is ready, then run it """
return func(*args, **kwargs)
def _get_instructions(code):
""" Parse dis.disco output """
buffer_ = StringIO()
stdout, sys.stdout = sys.stdout, buffer_
try:
disco(code)
finally:
sys.stdout = stdout
for match in finditer(r"(\d+) ([A-Z_]+)( +\d+)?", buffer_.getvalue()):
yield int(match.group(1)), match.group(2), int(match.group(3) or 0)
if __name__ == "__main__":
fn = _.get("hello").upper() # STORE_NAME
assert fn({"hello": "there"}) == "THERE"
assert str(fn) == "< _.get('hello').upper() >"
def test():
return _.get("hello").upper() # Different frame
assert test()({"hello": "there"}) == "THERE"
def test():
fn = _.get("hello").upper() # STORE_FAST
assert fn({"hello": "there"}) == "THERE"
test()
class T: pass
t = T()
t.fn = _.get("hello").upper() # type: ignore # STORE_ATTR
assert t.fn({"hello": "there"}) == "THERE" # type: ignore
d = {}
d["fn"] = _.get("hello").upper() # STORE_SUBSCR
assert d["fn"]({"hello": "there"}) == "THERE"
assert tuple(map(_.upper(), ["lower"])) == ("LOWER",) # Used in expression
assert tuple(map(_.index(int("1")), [[1,2]])) == (0,) # Function call in method
d = {"key": 1}
assert tuple(map(_.index(d.get("key")), [[1,2]])) == (0,) # Function method call in method
d = {"key": lambda: 0}
assert tuple(map(_["key"](), [d])) == (0,) # Function tail function call
d = {"key": lambda _: 0}
assert tuple(map(_["key"](str(1)), [d])) == (0,) # Function call in tail function call
assert tuple(map(_[1:3], [[1,2,3,4]])) == ([2,3],) # Slice in item
d = {"one": {"two": "three"}}
assert tuple(map(_["one"]["two"], [d])) == ("three",) # nested item calls
assert tuple(map(_.get("one")["two"], [d])) == ("three",) # nested function to item
d = {"key": lambda: lambda: lambda: 3}
assert tuple(map(_["key"]()()(), [d])) == (3,) # Super nested
fn = _ + 10
assert fn(3) == 13
fn = 10 + _
assert fn(3) == 13
fn = _ * 2
assert fn(10) == 20
fn = 2 * _
assert fn("-") == "--"
assert tuple(map((_ * 2).upper(), ["abc"])) == ("ABCABC",)
fn = _ - 5
assert fn(10) == 5
assert tuple(map(5 - _ + 10, [20])) == (-5,)
fn = _ + _
assert fn(5, 5) == 10
assert tuple(map(10 > _, [2, 4, 6, 8, 10, 12])) == (True, True, True, True, False, False)
assert tuple(map(abs(_), [-1, 2])) == (1,2)
assert tuple(map(-_ + 5, [10, 5])) == (-5, 0)
assert tuple(map(+_ + 5, [10, 5])) == (15, 10)
assert tuple(map(_ / 1, [2, 4])) == (2.0, 4.0)
fn = _ + 3
assert fn(5) == 5 + 3
fn = 3 + _
assert fn(5) == 3 + 5
fn = _ - 3
assert fn(5) == 5 - 3
fn = 3 - _
assert fn(5) == 3 - 5
fn = _ / 3
assert fn(5) == 5 / 3
fn = 3 / _
assert fn(5) == 3 / 5
fn = _ * 3
assert fn(5) == 5 * 3
fn = 3 * _
assert fn(5) == 3 * 5
fn = _ ** 3
assert fn(5) == 5 ** 3
fn = 3 ** _
assert fn(5) == 3 ** 5
fn = _ % 3
assert fn(5) == 5 % 3
fn = 3 % _
assert fn(5) == 3 % 5
fn = _ > 3
assert fn(5) == (5 > 3)
fn = 3 > _
assert fn(5) == (3 > 5)
fn = _ >= 3
assert fn(5) == (5 >= 3)
fn = 3 >= _
assert fn(5) == (3 >= 5)
fn = _ < 3
assert fn(5) == (5 < 3)
fn = 3 < _
assert fn(5) == (3 < 5)
fn = _ <= 3
assert fn(5) == (5 <= 3)
fn = 3 <= _
assert fn(5) == (3 <= 5)
fn = _ == 3
assert fn(5) == (5 == 3)
fn = 3 != _
assert fn(5) == (3 != 5)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment