def ordict(*args): """ pairs args (in order) and makes an OrderedDict with them >>> ordict(1,2, 3,4) OrderedDict([(1, 2), (3, 4)]) """ return OrderedDict(partition(args))
def _s_eval_helper(scope): assert len(optional) % 2 == 0 pairs = tuple(partition(optional)) keys, defaults = zip(*pairs) if pairs else ((), ()) defaults = S(entuple, *defaults).s_eval(scope) def Lambda(local): bindings = dict(zip(keys, defaults)) for k, v in local.items(): if v != _sentinel: bindings[k] = v return S(do, *body).s_eval(Scope(scope, bindings)) _sentinel = object() func = eval( '''lambda {0}:__builtins__[0](__builtins__[1]())'''.format( ','.join( ((','.join(required),) if required else ()) + ((','.join( map('{0}=_'.format, keys)),) if keys else ()) + (('*%s' % star,) if star else ()) + (('**' + stars,) if stars else ()))), # can't gensym, but __builtins__ should never be used as a parameter name dict(_=_sentinel, __builtins__=(Lambda, locals))) # TODO: set func defaults tuple, or is that an implementation detail? return func
def edict(*args, **kwargs): """ pairs args and makes a dictionary with them >>> edict(1, 2) {1: 2} >>> edict(1, 2, 3, 4, 5, 6)[3] 4 >>> edict(1, 2, ... 3, 4) == {1: 2, 3: 4} True kwargs become string keys >>> edict(1,2, c=3) == {1:2, 'c':3} True """ return dict(chain(partition(args), kwargs.items()))
def Try(thunk, *Except, **ElseFinally): """ wraps a try statement Try() returns the thunk's result normally >>> Try(lambda: 1+1) 2 Exception handlers are written as an exception type paired with a function. The exception handlers are required to take an argument, but they are not required to use it. Try() returns the exception handler's result on exceptions. This overrides both the normal thunk and else part's result. Else is not evaluated after exceptions. >>> Try(lambda: ... 1/0, # error ... ZeroDivisionError, lambda zdr: do( ... Print(zdr.__class__.__name__), ... 'returns: take a limit!',), ... Finally=lambda: ... Print('finally!'), ... Else=lambda: ... Print('returns: or else!')) ZeroDivisionError finally! 'returns: take a limit!' Try() evaluates to the else part if provided. >>> Try(lambda: ... 0/1, # allowed ... ZeroDivisionError, lambda zdr: do( ... Print(zdr), ... 'take a limit!',), ... Finally=lambda: ... Print('finally!'), ... Else=lambda: ... 'returns: or else!') finally! 'returns: or else!' Try() never returns the result of Finally(), which is only for side effects. Multiple exception handlers are allowed. They're checked in order. >>> Try(lambda: ... 1/0, ... ZeroDivisionError, lambda zdr: ... Print('by ZeroDivisionError'), ... Exception, lambda x: ... Print('by Exception'),) by ZeroDivisionError >>> Try(lambda: ... 1/0, ... Exception, lambda x: ... Print('by Exception'), ... ZeroDivisionError, lambda zdr: ... Print('by ZeroDivisionError'),) by Exception to catch any exception, like the final `except:`, use BaseException. """ assert set(ElseFinally.keys()) <= {'Else', 'Finally'} assert len(Except) % 2 == 0 assert all(issubclass(x, BaseException) for x, c in partition(Except)) Else = ElseFinally.get('Else', None) Finally = ElseFinally.get('Finally', Pass) try: res = thunk() except BaseException as ex: for ex_type, ex_handler in partition(Except): if isinstance(ex, ex_type): return ex_handler(ex) else: raise else: if Else: res = Else() finally: Finally() return res
def __init__(self, pairs): assert len(pairs) % 2 == 0 self.pairs = partition(pairs)