Skip to content

Instantly share code, notes, and snippets.

@DomNomNom
Last active April 28, 2016 01:37
Show Gist options
  • Select an option

  • Save DomNomNom/282cc4f2d5806c7d61a59baeb63eed19 to your computer and use it in GitHub Desktop.

Select an option

Save DomNomNom/282cc4f2d5806c7d61a59baeb63eed19 to your computer and use it in GitHub Desktop.
"""
The main use case of this is to replace either
>>> [ x * (x + 1) for x in [1,2,3] ]
or
>>> map(lambda x: x * (x + 1), [1,2,3])
with
>>> map(X * (X + 1), [1,2,3]) #SWAG
You can naively think of it as 'lambda X:' without writing 'lambda X:'.
This allows you to make the all important tradeoff between typing fewer
characters and sanity. If you see this in production, quit your job.
See the examples at the bottom of this file for some do's/don'ts.
"""
class _X(object):
def __init__(self, _fun=None):
""" _fun is a function taking a single argument. """
if _fun is None:
_fun = lambda x: x
self._fun = _fun
def __getattr__(self, attribute): # allow arbitrary function access
return _X(lambda x: getattr(self._fun(x), attribute))
def __call__(self, element):
return self._fun(element)
# some helper magic to make X work
def _call_if_X(other, x):
if type(other) is _X:
return other(x)
return other
def createAttr(attr_name):
""" Docstring left to the reader as an excercise. """
return lambda self, *others: _X(lambda x: getattr(self(x), attr_name)(
*map(_call_if_X, others, [x]*len(others))
))
def formatBuiltinNames(names):
return [ '__{}__'.format(name) for name in names ]
builtins = 'pos neg abs add sub mod mul div floordiv rshift lshift radd rsub rmod rmul rdiv rfloordiv rrshift rlshift getitem'
for attr_name in formatBuiltinNames(builtins.split()):
setattr(_X, attr_name, createAttr(attr_name))
X = _X() # Instantiate the one, the only, -== X ==-
# ====== Examples / Tests ======
if __name__ == '__main__':
def test(expected, actual):
print actual
assert expected == actual
test( [ x for x in [1,2,3] ], map(X, [1,2,3]) ) # do nothing with the data
test( [ x + 10 for x in [1,2,3] ], map(X + 10, [1,2,3]) ) # add for each integer, add an integer
test( [ x + 10 * 3 for x in [1,2,3] ], map(X + 10 * 3, [1,2,3]) ) # add 30. (correct order of operations)
test( [ (x + 10) * 3 for x in [1,2,3] ], map((X + 10) * 3, [1,2,3]) ) # more order of operations
test( [ 3 - x for x in [-1,-2,-3] ], map(3 - X, [-1,-2,-3]) ) # subtracting
test( [ 3 + -x for x in [-1,-2,-3] ], map(3 + -X, [-1,-2,-3]) ) # adding a negative
test( [ 1 << -x for x in [-1,-2,-3] ], map(1 << -X, [-1,-2,-3]) ) # weird operators
test( [ x * (x+1) for x in [1,2,3] ], map(X * (X + 1), [1,2,3]) ) # multiple Xs in the same expression
test( [ -abs(x) for x in [-1, 0, 1] ], map(-abs(X), [-1, 0, 1]) ) # how about some builtin functions
# other types work too!
test( # string concatenation
[ x + "! :D" for x in ['fun', 'games'] ],
map( X + "! :D" , ['fun', 'games'])
)
test( # grabbing data out of a dict
[ x['data'] + 3 for x in [{'data':3}, {'data':33}] ],
map(X['data'] + 3, [{'data':3}, {'data':33}])
)
# getting members of classes works too
class Foo(object):
def __init__(self, data):
self.data = data
test(
[ x.data for x in [Foo(3), Foo(2)]],
(map(X.data, [Foo(3), Foo(2)]))
)
test( # nest it all you like
[ 10 - x.data.data for x in [Foo(Foo(2)), Foo(Foo(3))]],
map(10 - X.data.data, [Foo(Foo(2)), Foo(Foo(3))])
)
# ====== things that are not possible (shhhh) ======
# can't tell if being called by map or within X.
# possibly fixable with stack inspection (are we being called by map?)
# print [ x.zfill(4) for x in '1 12 100'.split() ]
# print map((X.zfill)(3), '1 12 100'.split())
# print [ '3'.zfill(x) for x in [1,2,3] ]
# print map('3'.zfill(X), [1,2,3]) # zfill needs to take an int.
# print [ int(x) for x in "1 2 3".split() ]
# print map(int(X), "1 2 3".split()) # int() needs to return an int
# string does not have __radd__ (only __add__)
# print [ ":" + x for x in ['3'] ]
# print map( ":" + X, ['3'])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment