from typing import Iterable
from typing import Any
from typing import Callable
from typing import Tuple
from typing import Iterator
import itertools


def partition(
        iterable: Iterable[Any],
        *,
        by: Callable[[Any], bool],
) -> Tuple[Iterator, Iterator]:
    """Split an iterable into two iterators based upon a condition.

    Returns two iteators, one for which the condition is False, and one for
    which the condition is True.

    The condition is specified by the required keyword argument by, which just
    be a callable returning True or False based upon the value of one argument.
    It will be called for each item in the iterable in sequence.

    Arguments:
        iterable: object for which items are to be partitioned

    Keyword Arguments:
        by: callable which takes one argument and returns a bool

    Returns:
        a tuple of two iterators, the first of which iterates over all items of
        the original iterable for which the condition is False, and the other
        for which the condition is True

    Examples:

    >>> odd, even = partition(range(10), by=lambda n: n % 2 == 0)
    >>> list(odd)
    [1, 3, 5, 7, 9]
    >>> list(even)
    [0, 2, 4, 6, 8]
    >>> text = 'We hold these truths to be self-evident'.split()
    >>> short, long = partition(text, by=lambda s: len(s) > 4)
    >>> list(short)
    ['We', 'hold', 'to', 'be']
    >>> list(long)
    ['these', 'truths', 'self-evident']

    """
    false_it, true_it = itertools.tee(iterable)
    return (itertools.filterfalse(by, false_it), filter(by, true_it))