Python collections in a functional-programming style.

functional iterables itertools
pip install functional_itertools==0.8.1



PyPI version Build Status codecov


functional_itertools provides a set of classes which make it easy to chain iterables in a functional-programming style. These objects are based on the typing module:

class subclass of
CIterable typing.Iterable
CList typing.List
CSet typing.Set
CFrozenSet typing.FrozenSet
CDict typing.Dict

These classes:

  • have access to all Python built-in functions relating to iterables, as well as those from itertools and more.
  • are generic, and thus can be type-checked.
  • can be used with third-party iterables (e.g., more-itertools via the pipe method.
  • are easily extensible by virtue of being offered as simple classes (e.g., no multiple-inheritance, no metaclasses, etc).


Given code like this:

res = []
for x in range(10):
    y = 2 * x
    if 3 <= y <= 15:
        z = y - 1
        if z >= 6:
assert res == [7, 9, 11, 13]

You can reduce the complexity by using generator expressions and list comprehensions instead of nesting:

x = range(10)
y = (2*i for i in x)
z = (i for i in y if 3 <= i <= 15)
a = (i-1 for i in z)
res = [i for i in a if i >= 6]

You can further reduce the number of variables used by adopting a functional programming style:

x = range(10)
y = map(lambda i: 2*i, x)
z = filter(lambda i: 3 <= i <= 15, y)
a = map(lambda i: i-1, z)
res = list(filter(lambda i: i >= 6, a))

Finally, you can further reduce the number of variables used by using CIterable:

from functional_itertools import CIterable

res = (
    .map(lambda i: 2*i)
    .filter(lambda i: 3 <= i <= 15)
    .map(lambda i: i-1)
    .filter(lambda i: i >= 6)

The edge in clarity scales as the number of operations increase. If you're a fan of this look and way of thinking then, functional_itertools is for you!

As mentioned, you have access to all functions from itertools as functools as well, you can write:

from functional_itertools import CIterable

res = (
    CIterable(["a", "b", "c", "d", "e", "f", "g"])
    .islice(2, 5)
    .map(lambda i: 2*i)
    .reduce(lambda i, j: "_".join([i, j]))
assert res == "cc_dd_ee"

API reference (warning: implementation still a WIP!)

Please note that for CDict has 3 methods per listing, i.e., instead of .all(), it has .all_keys(), .all_values() and .all_items() instead.

type method CIterable CList CSet CFrozenSet CDict
built-in self.all()
built-in self.any()
built-in self.enumerate(start=0)
built-in self.filter(function)
built-in self.len()
built-in, *iterables)
built-in self.max(*, key, default)
built-in self.min(*, key, default)
built-in cls.range(stop) cls.range(start, stop [,step])
built-in self.reversed()
built-in self.sum(/, start=0)
built-in self.tuple()
built-in1 self.dict()
built-in1 self.frozenset()
built-in1 self.list()
built-in1 self.set()
built-in1 self.sorted(key=None, reverse=False)
itertools cls.count(start[, step])
itertools self.cycle()
itertools cls.repeat(object[, times])
itertools self.accumulate(func) (3.6, 3.7) self.accumulate(func, *, initial=None) (3.8)
itertools self.chain(*iterables)
functools self.reduce(function[, initializer])
functools2 self.reduce_as_iterable(function[, initializer])
pathlib cls.iterdir(path)
  • 1 These methods return the functional_itertools classes, namely, CIterable, CList, etc.
  • 2 This method wraps an iterable-yielding reduction in a CIterable.

See also