| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent c87d9f4 commit 9718b59
5 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -86,29 +86,38 @@ The following module functions all construct and return iterators. Some provide | |||
| 86 | 86 | streams of infinite length, so they should only be accessed by functions or | |
| 87 | 87 | loops that truncate the stream. | |
| 88 | 88 | ||
| 89 | - .. function:: accumulate(iterable[, func]) | ||
| 89 | + .. function:: accumulate(iterable[, func, *, initial=None]) | ||
| 90 | 90 | ||
| 91 | 91 | Make an iterator that returns accumulated sums, or accumulated | |
| 92 | 92 | results of other binary functions (specified via the optional | |
| 93 | - *func* argument). If *func* is supplied, it should be a function | ||
| 93 | + *func* argument). | ||
| 94 | + | ||
| 95 | + If *func* is supplied, it should be a function | ||
| 94 | 96 | of two arguments. Elements of the input *iterable* may be any type | |
| 95 | 97 | that can be accepted as arguments to *func*. (For example, with | |
| 96 | 98 | the default operation of addition, elements may be any addable | |
| 97 | 99 | type including :class:`~decimal.Decimal` or | |
| 98 | - :class:`~fractions.Fraction`.) If the input iterable is empty, the | ||
| 99 | - output iterable will also be empty. | ||
| 100 | + :class:`~fractions.Fraction`.) | ||
| 101 | + | ||
| 102 | + Usually, the number of elements output matches the input iterable. | ||
| 103 | + However, if the keyword argument *initial* is provided, the | ||
| 104 | + accumulation leads off with the *initial* value so that the output | ||
| 105 | + has one more element than the input iterable. | ||
| 100 | 106 | ||
| 101 | 107 | Roughly equivalent to:: | |
| 102 | 108 | ||
| 103 | - def accumulate(iterable, func=operator.add): | ||
| 109 | + def accumulate(iterable, func=operator.add, *, initial=None): | ||
| 104 | 110 | 'Return running totals' | |
| 105 | 111 | # accumulate([1,2,3,4,5]) --> 1 3 6 10 15 | |
| 112 | + # accumulate([1,2,3,4,5], initial=100) --> 100 101 103 106 110 115 | ||
| 106 | 113 | # accumulate([1,2,3,4,5], operator.mul) --> 1 2 6 24 120 | |
| 107 | 114 | it = iter(iterable) | |
| 108 | - try: | ||
| 109 | - total = next(it) | ||
| 110 | - except StopIteration: | ||
| 111 | - return | ||
| 115 | + total = initial | ||
| 116 | + if initial is None: | ||
| 117 | + try: | ||
| 118 | + total = next(it) | ||
| 119 | + except StopIteration: | ||
| 120 | + return | ||
| 112 | 121 | yield total | |
| 113 | 122 | for element in it: | |
| 114 | 123 | total = func(total, element) | |
@@ -152,6 +161,9 @@ loops that truncate the stream. | |||
| 152 | 161 | .. versionchanged:: 3.3 | |
| 153 | 162 | Added the optional *func* parameter. | |
| 154 | 163 | ||
| 164 | + .. versionchanged:: 3.8 | ||
| 165 | + Added the optional *initial* parameter. | ||
| 166 | + | ||
| 155 | 167 | .. function:: chain(*iterables) | |
| 156 | 168 | ||
| 157 | 169 | Make an iterator that returns elements from the first iterable until it is | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -147,6 +147,12 @@ def test_accumulate(self): | |||
| 147 | 147 | list(accumulate(s, chr)) # unary-operation | |
| 148 | 148 | for proto in range(pickle.HIGHEST_PROTOCOL + 1): | |
| 149 | 149 | self.pickletest(proto, accumulate(range(10))) # test pickling | |
| 150 | + self.pickletest(proto, accumulate(range(10), initial=7)) | ||
| 151 | + self.assertEqual(list(accumulate([10, 5, 1], initial=None)), [10, 15, 16]) | ||
| 152 | + self.assertEqual(list(accumulate([10, 5, 1], initial=100)), [100, 110, 115, 116]) | ||
| 153 | + self.assertEqual(list(accumulate([], initial=100)), [100]) | ||
| 154 | + with self.assertRaises(TypeError): | ||
| 155 | + list(accumulate([10, 20], 100)) | ||
| 150 | 156 | ||
| 151 | 157 | def test_chain(self): | |
| 152 | 158 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1 @@ | |||
| 1 | + Add an optional *initial* argument to itertools.accumulate(). | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -3475,6 +3475,7 @@ typedef struct { | |||
| 3475 | 3475 | PyObject *total; | |
| 3476 | 3476 | PyObject *it; | |
| 3477 | 3477 | PyObject *binop; | |
| 3478 | + PyObject *initial; | ||
| 3478 | 3479 | } accumulateobject; | |
| 3479 | 3480 | ||
| 3480 | 3481 | static PyTypeObject accumulate_type; | |
@@ -3484,18 +3485,19 @@ static PyTypeObject accumulate_type; | |||
| 3484 | 3485 | itertools.accumulate.__new__ | |
| 3485 | 3486 | iterable: object | |
| 3486 | 3487 | func as binop: object = None | |
| 3488 | + * | ||
| 3489 | + initial: object = None | ||
| 3487 | 3490 | Return series of accumulated sums (or other binary function results). | |
| 3488 | 3491 | [clinic start generated code]*/ | |
| 3489 | 3492 | ||
| 3490 | 3493 | static PyObject * | |
| 3491 | 3494 | itertools_accumulate_impl(PyTypeObject *type, PyObject *iterable, | |
| 3492 | - PyObject *binop) | ||
| 3493 | - /*[clinic end generated code: output=514d0fb30ba14d55 input=6d9d16aaa1d3cbfc]*/ | ||
| 3495 | + PyObject *binop, PyObject *initial) | ||
| 3496 | + /*[clinic end generated code: output=66da2650627128f8 input=c4ce20ac59bf7ffd]*/ | ||
| 3494 | 3497 | { | |
| 3495 | 3498 | PyObject *it; | |
| 3496 | 3499 | accumulateobject *lz; | |
| 3497 | 3500 | ||
| 3498 | - | ||
| 3499 | 3501 | /* Get iterator. */ | |
| 3500 | 3502 | it = PyObject_GetIter(iterable); | |
| 3501 | 3503 | if (it == NULL) | |
@@ -3514,6 +3516,8 @@ itertools_accumulate_impl(PyTypeObject *type, PyObject *iterable, | |||
| 3514 | 3516 | } | |
| 3515 | 3517 | lz->total = NULL; | |
| 3516 | 3518 | lz->it = it; | |
| 3519 | + Py_XINCREF(initial); | ||
| 3520 | + lz->initial = initial; | ||
| 3517 | 3521 | return (PyObject *)lz; | |
| 3518 | 3522 | } | |
| 3519 | 3523 | ||
@@ -3524,6 +3528,7 @@ accumulate_dealloc(accumulateobject *lz) | |||
| 3524 | 3528 | Py_XDECREF(lz->binop); | |
| 3525 | 3529 | Py_XDECREF(lz->total); | |
| 3526 | 3530 | Py_XDECREF(lz->it); | |
| 3531 | + Py_XDECREF(lz->initial); | ||
| 3527 | 3532 | Py_TYPE(lz)->tp_free(lz); | |
| 3528 | 3533 | } | |
| 3529 | 3534 | ||
@@ -3533,6 +3538,7 @@ accumulate_traverse(accumulateobject *lz, visitproc visit, void *arg) | |||
| 3533 | 3538 | Py_VISIT(lz->binop); | |
| 3534 | 3539 | Py_VISIT(lz->it); | |
| 3535 | 3540 | Py_VISIT(lz->total); | |
| 3541 | + Py_VISIT(lz->initial); | ||
| 3536 | 3542 | return 0; | |
| 3537 | 3543 | } | |
| 3538 | 3544 | ||
@@ -3541,6 +3547,13 @@ accumulate_next(accumulateobject *lz) | |||
| 3541 | 3547 | { | |
| 3542 | 3548 | PyObject *val, *newtotal; | |
| 3543 | 3549 | ||
| 3550 | + if (lz->initial != Py_None) { | ||
| 3551 | + lz->total = lz->initial; | ||
| 3552 | + Py_INCREF(Py_None); | ||
| 3553 | + lz->initial = Py_None; | ||
| 3554 | + Py_INCREF(lz->total); | ||
| 3555 | + return lz->total; | ||
| 3556 | + } | ||
| 3544 | 3557 | val = (*Py_TYPE(lz->it)->tp_iternext)(lz->it); | |
| 3545 | 3558 | if (val == NULL) | |
| 3546 | 3559 | return NULL; | |
@@ -3567,6 +3580,19 @@ accumulate_next(accumulateobject *lz) | |||
| 3567 | 3580 | static PyObject * | |
| 3568 | 3581 | accumulate_reduce(accumulateobject *lz, PyObject *Py_UNUSED(ignored)) | |
| 3569 | 3582 | { | |
| 3583 | + if (lz->initial != Py_None) { | ||
| 3584 | + PyObject *it; | ||
| 3585 | + | ||
| 3586 | + assert(lz->total == NULL); | ||
| 3587 | + if (PyType_Ready(&chain_type) < 0) | ||
| 3588 | + return NULL; | ||
| 3589 | + it = PyObject_CallFunction((PyObject *)&chain_type, "(O)O", | ||
| 3590 | + lz->initial, lz->it); | ||
| 3591 | + if (it == NULL) | ||
| 3592 | + return NULL; | ||
| 3593 | + return Py_BuildValue("O(NO)O", Py_TYPE(lz), | ||
| 3594 | + it, lz->binop?lz->binop:Py_None, Py_None); | ||
| 3595 | + } | ||
| 3570 | 3596 | if (lz->total == Py_None) { | |
| 3571 | 3597 | PyObject *it; | |
| 3572 | 3598 | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments