Skip to content

Instantly share code, notes, and snippets.

@simon-engledew
Created September 20, 2012 12:48
Show Gist options
  • Save simon-engledew/3755683 to your computer and use it in GitHub Desktop.
Save simon-engledew/3755683 to your computer and use it in GitHub Desktop.
Python ForEach Naughtiness
import __builtin__
import operator
def merge(a, b):
a = a.copy()
a.update(b)
return a
class curry(object):
def __init__(self, fn, *args, **kwargs):
self.fn = fn
self.args = args
self.kwargs = kwargs.copy()
def __call__(self, *args, **kwargs):
return self.fn(*(self.args + args), **merge(self.kwargs, kwargs))
def die(message, cls=Exception):
"""
Raise an exception, allows you to use logical shortcut operators to test for object existence succinctly.
User.by_name('username') or die('Failed to find user')
"""
raise cls(message)
def unguido(self, key):
"""
Attempt to find methods which should really exist on the object instance.
"""
return curry((getattr(__builtin__, key, None) if hasattr(__builtin__, key) else getattr(operator, key, None)) or die(key, KeyError), self)
class mapper(object):
def __init__(self, iterator, key):
self.iterator = iterator
self.key = key
self.fn = lambda o: getattr(o, key)
def __getattribute__(self, key):
if key in ('iterator', 'fn', 'key'): return object.__getattribute__(self, key)
return mapper(self, key)
def __call__(self, *args, **kwargs):
self.fn = lambda o: (getattr(o, self.key, None) or unguido(o, self.key))(*args, **kwargs)
return self
def __iter__(self):
for value in self.iterator:
yield self.fn(value)
class foreach(object):
"""
Creates an output iterator which will apply any functions called on it to every element
in the input iterator. A kind of chainable version of filter().
E.g:
foreach([1, 2, 3]).__add__(2).__str__().replace('3', 'a').upper()
is equivalent to:
(str(o + 2).replace('3', 'a').upper() for o in iterator)
Obviously this will probably perform poorly and is not 'Pythonic'.
"""
def __init__(self, iterator):
self.iterator = iterator
def __getattribute__(self, key):
if key in ('iterator',): return object.__getattribute__(self, key)
return mapper(self.iterator, key)
def __iter__(self):
for value in self.iterator:
yield value
if __name__ == '__main__':
print list(foreach([1, 2, 3]).add(2).str().replace('3', 'a').upper())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment