-
-
Save DomNomNom/282cc4f2d5806c7d61a59baeb63eed19 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
| """ | |
| 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