Фильтрация и накопление результата
Содержание курса
Паттерн аккумулятора: сумма и произведение
Фильтрация возвращает список — подмножество исходного. Аккумулятор работает иначе: в конце получаем одно число, которое накапливалось по ходу перебора.
Начнём с чистого случая — сумма всех элементов без каких-либо условий:
def sum_all(numbers):
total = 0
for n in numbers:
total += n
return total
print(sum_all([3, -1, 7, -4, 2]))
# 7
total += n — сокращение от total = total + n. После каждой итерации total хранит промежуточный результат, и к концу цикла в нём оказывается итоговая сумма. Начальное значение 0 — нейтральный элемент сложения: 0 + x = x, поэтому первая итерация не искажает результат.
Для произведения структура та же, но начальное значение — 1, а оператор — *=:
def product_of(numbers):
product = 1
for n in numbers:
product *= n
return product
print(product_of([2, 3, 4]))
# 24
Почему именно 1? Потому что 1 — нейтральный элемент умножения: 1 * x = x. Если начать с 0, первое же умножение обнулит аккумулятор, и он останется нулём независимо от содержимого списка. Это одна из самых распространённых ошибок при переносе паттерна суммы на произведение:
# Неправильно — результат всегда 0
def broken_product(numbers):
product = 0 # ← ошибка
for n in numbers:
product *= n
return product
print(broken_product([2, 3, 4]))
# 0 — не то, что ожидалось
Запомнить легко: нулевая инициализация подходит только сложению. Для умножения — всегда 1.
Аккумулятор можно комбинировать с условием if внутри цикла — тогда накапливаются только подходящие элементы. Это расширение базового паттерна, а не его обязательная часть:
def sum_positive(numbers):
total = 0
for n in numbers:
if n > 0: # ← накапливаем только положительные
total += n
return total
print(sum_positive([3, -1, 7, -4, 2]))
# 12
Обратите внимание: без if цикл обрабатывал бы все элементы подряд. Условие здесь — дополнительный фильтр внутри накопления, а не часть самого паттерна аккумулятора.
