def try_(block, except_=None, else_=None, finally_=None):
    ensure_callable(block)
    if not (except_ or else_ or finally_):
        raise TypeError("at least one of `except_`, `else_` or `finally_` "
                        "functions must be provided")
    if else_ and not except_:
        raise TypeError("`else_` can only be provided along with `except_`")
    if except_:
        if callable(except_):
            except_ = [(Exception, except_)]
        else:
            ensure_iterable(except_)
            if is_mapping(except_):
                ensure_ordered_mapping(except_)
                except_ = except_.items()
        def handle_exception():
            exc_type, exc_object = sys.exc_info()[:2]
            for t, handler in except_:
                if issubclass(exc_type, t):
                    return handler(exc_object)
            raise
        if else_:
            ensure_callable(else_)
            if finally_:
                ensure_callable(finally_)
                try:
                    block()
                except:
                    return handle_exception()
                else:
                    return else_()
                finally:
                    finally_()
            else:
                try:
                    block()
                except:
                    return handle_exception()
                else:
                    return else_()
        else:
            if finally_:
                ensure_callable(finally_)
                try:
                    return block()
                except:
                    return handle_exception()
                finally:
                    finally_()
            else:
                try:
                    return block()
                except:
                    return handle_exception()
    elif finally_:
        ensure_callable(finally_)
        try:
            return block()
        finally:
            finally_()