Skip to content

Accumulators

graph TD
  Z(["<code>sum(iterable, initial=initial, default=default)</code>"]) --> A{"<code>initial</code> <code>MISSING</code>?"};
  A --> |no| B["<code>return initial+...</code>"];
  A --> |yes| C{"<code>iterable</code> empty?"};
  C --> |no| D["<code>return iterable[0]+...</code>"];
  C --> |yes| E{"<code>default</code> <code>MISSING</code>?"};
  E --> |no| F["<code>return default</code>"];
  E --> |yes| G["<code>raise TypeError</code>"];

MISSING module-attribute

MISSING = object()

Sentinel to mark empty parameters.

exception_generator

exception_generator(ex=IndexError)

Raise the provided exception on the first yield.

>>> sum(islice(chain([1, 2, 3], exception_generator()), 3))
6
>>> sum(islice(chain([1, 2, 3], exception_generator()), 4))
Traceback (most recent call last):
  ...
IndexError

Used to ensure that iteration doesn't go to far.

Source code in operationcounter\accumulators.py
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
def exception_generator(ex=IndexError):
    """Raise the provided exception on the first yield.

    ```python
    >>> sum(islice(chain([1, 2, 3], exception_generator()), 3))
    6
    >>> sum(islice(chain([1, 2, 3], exception_generator()), 4))
    Traceback (most recent call last):
      ...
    IndexError
    ```

    Used to ensure that iteration doesn't go to far.
    """
    raise ex
    yield

group_ordinal

group_ordinal(*iterables)

Group elements of iterables by their ordinal.

>>> iterables = (1, 2, 3), [4, 5, 6, 7], {8}
>>> list(group_ordinal(*iterables))
[(1, 4, 8), (2, 5), (3, 6), (7,)]

The elements are grouped in the same order as their iterables (stable).

References
Source code in operationcounter\accumulators.py
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
def group_ordinal(*iterables):
    """Group elements of iterables by their ordinal.

    ```python
    >>> iterables = (1, 2, 3), [4, 5, 6, 7], {8}
    >>> list(group_ordinal(*iterables))
    [(1, 4, 8), (2, 5), (3, 6), (7,)]
    ```

    The elements are grouped in the same order as their iterables (stable).

    References
    ----------
    - [more-itertools PR #1073](https://github.com/more-itertools/more-itertools/pull/1073)
    """
    iterators = list(map(iter, reversed(iterables)))
    result = []
    while iterators:
        result.clear()
        for i in reversed(range(len(iterators))):
            try:
                result.append(next(iterators[i]))
            except StopIteration:
                del iterators[i]
        if result:
            yield tuple(result)

reduce_default

reduce_default(
    function, iterable, *, initial=MISSING, default=0
)

Apply function of two arguments cumulatively to the iterable.

Like functools.reduce but with an optional initial element and an optional default return value. Difference to functools.reduce:

  • If iterable is empty and initial and default are MISSING, a TypeError is raised.
  • If iterable is empty and initial is MISSING, but default is not, then default is returned.
Source code in operationcounter\accumulators.py
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
def reduce_default(function, iterable, *, initial=MISSING, default=0):
    """Apply function of two arguments cumulatively to the iterable.

    Like `functools.reduce` but with an optional initial element and an
    optional default return value.
    Difference to `functools.reduce`:

    - If `iterable` is empty and `initial` and `default` are `MISSING`, a
      `TypeError` is raised.
    - If `iterable` is empty and `initial` is `MISSING`, but `default` is not,
      then `default` is returned.
    """
    if initial is not MISSING:
        return reduce(function, iterable, initial)
    else:
        it = iter(iterable)
        try:
            initial = next(it)
        except StopIteration:
            if default is not MISSING:
                return default
            else:
                raise TypeError("accumulation of empty iterable with no" \
                        + " initial or default value")
        return reduce(function, it, initial)

sum_default

sum_default(iterable, *, initial=MISSING, default=0)

Return the sum of all elements in the iterable.

Like sum but with an optional initial element and an optional default return value.

  • If iterable is empty and initial and default are MISSING, a TypeError is raised.
  • If iterable is empty and initial is MISSING, but default is not, then default is returned.
  • If initial is MISSING, then there is truly no initial 0+=.
Source code in operationcounter\accumulators.py
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
def sum_default(iterable, *, initial=MISSING, default=0):
    """Return the sum of all elements in the iterable.

    Like `sum` but with an optional initial element and an optional default
    return value.

    - If `iterable` is empty and `initial` and `default` are `MISSING`, a
      `TypeError` is raised.
    - If `iterable` is empty and `initial` is `MISSING`, but `default` is not,
      then `default` is returned.
    - If `initial` is `MISSING`, then there is truly no initial `0+=`.
    """
    if initial is not MISSING:
        return sum(iterable, initial)
    else:
        it = iter(iterable)
        try:
            initial = next(it)
        except StopIteration:
            if default is not MISSING:
                return default
            else:
                raise TypeError("accumulation of empty iterable with no" \
                        + " initial or default value")
        return sum(it, start=initial)

prod_default

prod_default(iterable, *, initial=MISSING, default=1)

Return the product of all elements in the iterable.

Like math.prod but with an optional initial element and an optional default return value.

  • If iterable is empty and initial are default is MISSING, a TypeError is raised.
  • If iterable is empty and initial is MISSING, but default is not, then default is returned.
  • If initial is MISSING, then there is truly no initial 1*=.
Source code in operationcounter\accumulators.py
108
109
110
111
112
113
114
115
116
117
118
119
120
121
def prod_default(iterable, *, initial=MISSING, default=1):
    """Return the product of all elements in the iterable.

    Like `math.prod` but with an optional initial element and an optional
    default return value.

    - If `iterable` is empty and `initial` are `default` is `MISSING`, a
      `TypeError` is raised.
    - If `iterable` is empty and `initial` is `MISSING`, but `default` is not,
      then `default` is returned.
    - If `initial` is `MISSING`, then there is truly no initial `1*=`.
    """
    #don't use math.prod, as it may reject non-numeric values
    return reduce_default(mul, iterable, initial=initial, default=default)

sumprod_default

sumprod_default(a, b, *, initial=MISSING, default=0)

Return the sum-product of all elements in the iterables.

Like math.sumprod but with an optional initial element, an optional default return value and non-strict zipping of both iterables.

  • If a or b is empty and initial and default are MISSING, a TypeError is raised.
  • If a or b is empty and initial is MISSING, but default is not, then default is returned.
  • If initial is MISSING, then there is truly no initial 0+=.
Source code in operationcounter\accumulators.py
123
124
125
126
127
128
129
130
131
132
133
134
135
def sumprod_default(a, b, *, initial=MISSING, default=0):
    """Return the sum-product of all elements in the iterables.

    Like `math.sumprod` but with an optional initial element, an optional
    default return value and non-strict zipping of both iterables.

    - If `a` or `b` is empty and `initial` and `default` are `MISSING`, a
      `TypeError` is raised.
    - If `a` or `b` is empty and `initial` is `MISSING`, but `default` is not,
      then `default` is returned.
    - If `initial` is `MISSING`, then there is truly no initial `0+=`.
    """
    return sum_default(map(mul, a, b), initial=initial, default=default)